OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "crash-reporter/crash_collector.h" | 5 #include "crash-reporter/crash_collector.h" |
6 | 6 |
7 #include <dirent.h> | 7 #include <dirent.h> |
8 #include <pwd.h> // For struct passwd. | 8 #include <pwd.h> // For struct passwd. |
9 #include <sys/types.h> // for mode_t. | 9 #include <sys/types.h> // for mode_t. |
10 | 10 |
| 11 #include <set> |
| 12 |
11 #include "base/file_util.h" | 13 #include "base/file_util.h" |
12 #include "base/logging.h" | 14 #include "base/logging.h" |
13 #include "base/string_util.h" | 15 #include "base/string_util.h" |
14 #include "crash-reporter/system_logging.h" | 16 #include "crash-reporter/system_logging.h" |
15 | 17 |
16 static const char kDefaultUserName[] = "chronos"; | 18 static const char kDefaultUserName[] = "chronos"; |
| 19 static const char kLsbRelease[] = "/etc/lsb-release"; |
17 static const char kSystemCrashPath[] = "/var/spool/crash"; | 20 static const char kSystemCrashPath[] = "/var/spool/crash"; |
18 static const char kUserCrashPath[] = "/home/chronos/user/crash"; | 21 static const char kUserCrashPath[] = "/home/chronos/user/crash"; |
19 | 22 |
20 // Directory mode of the user crash spool directory. | 23 // Directory mode of the user crash spool directory. |
21 static const mode_t kUserCrashPathMode = 0755; | 24 static const mode_t kUserCrashPathMode = 0755; |
22 | 25 |
23 // Directory mode of the system crash spool directory. | 26 // Directory mode of the system crash spool directory. |
24 static const mode_t kSystemCrashPathMode = 01755; | 27 static const mode_t kSystemCrashPathMode = 01755; |
25 | 28 |
26 static const uid_t kRootOwner = 0; | 29 static const uid_t kRootOwner = 0; |
(...skipping 21 matching lines...) Expand all Loading... |
48 SystemLogging *logger) { | 51 SystemLogging *logger) { |
49 CHECK(count_crash_function != NULL); | 52 CHECK(count_crash_function != NULL); |
50 CHECK(is_feedback_allowed_function != NULL); | 53 CHECK(is_feedback_allowed_function != NULL); |
51 CHECK(logger != NULL); | 54 CHECK(logger != NULL); |
52 | 55 |
53 count_crash_function_ = count_crash_function; | 56 count_crash_function_ = count_crash_function; |
54 is_feedback_allowed_function_ = is_feedback_allowed_function; | 57 is_feedback_allowed_function_ = is_feedback_allowed_function; |
55 logger_ = logger; | 58 logger_ = logger; |
56 } | 59 } |
57 | 60 |
| 61 std::string CrashCollector::Sanitize(const std::string &name) { |
| 62 std::string result = name; |
| 63 for (size_t i = 0; i < name.size(); ++i) { |
| 64 if (!isalnum(result[i]) && result[i] != '_') |
| 65 result[i] = '_'; |
| 66 } |
| 67 return result; |
| 68 } |
| 69 |
58 std::string CrashCollector::FormatDumpBasename(const std::string &exec_name, | 70 std::string CrashCollector::FormatDumpBasename(const std::string &exec_name, |
59 time_t timestamp, | 71 time_t timestamp, |
60 pid_t pid) { | 72 pid_t pid) { |
61 struct tm tm; | 73 struct tm tm; |
62 localtime_r(×tamp, &tm); | 74 localtime_r(×tamp, &tm); |
| 75 std::string sanitized_exec_name = Sanitize(exec_name); |
63 return StringPrintf("%s.%04d%02d%02d.%02d%02d%02d.%d", | 76 return StringPrintf("%s.%04d%02d%02d.%02d%02d%02d.%d", |
64 exec_name.c_str(), | 77 sanitized_exec_name.c_str(), |
65 tm.tm_year + 1900, | 78 tm.tm_year + 1900, |
66 tm.tm_mon + 1, | 79 tm.tm_mon + 1, |
67 tm.tm_mday, | 80 tm.tm_mday, |
68 tm.tm_hour, | 81 tm.tm_hour, |
69 tm.tm_min, | 82 tm.tm_min, |
70 tm.tm_sec, | 83 tm.tm_sec, |
71 pid); | 84 pid); |
72 } | 85 } |
73 | 86 |
74 FilePath CrashCollector::GetCrashDirectoryInfo( | 87 FilePath CrashCollector::GetCrashDirectoryInfo( |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 | 179 |
167 // Return true if the given crash directory has not already reached | 180 // Return true if the given crash directory has not already reached |
168 // maximum capacity. | 181 // maximum capacity. |
169 bool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) { | 182 bool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) { |
170 DIR* dir = opendir(crash_directory.value().c_str()); | 183 DIR* dir = opendir(crash_directory.value().c_str()); |
171 if (!dir) { | 184 if (!dir) { |
172 return false; | 185 return false; |
173 } | 186 } |
174 struct dirent ent_buf; | 187 struct dirent ent_buf; |
175 struct dirent* ent; | 188 struct dirent* ent; |
176 int count_non_core = 0; | |
177 int count_core = 0; | |
178 bool full = false; | 189 bool full = false; |
| 190 std::set<std::string> basenames; |
179 while (readdir_r(dir, &ent_buf, &ent) == 0 && ent != NULL) { | 191 while (readdir_r(dir, &ent_buf, &ent) == 0 && ent != NULL) { |
180 if ((strcmp(ent->d_name, ".") == 0) || | 192 if ((strcmp(ent->d_name, ".") == 0) || |
181 (strcmp(ent->d_name, "..") == 0)) | 193 (strcmp(ent->d_name, "..") == 0)) |
182 continue; | 194 continue; |
183 | 195 |
184 if (strcmp(ent->d_name + strlen(ent->d_name) - 5, ".core") == 0) { | 196 std::string filename(ent->d_name); |
185 ++count_core; | 197 size_t last_dot = filename.rfind("."); |
186 } else { | 198 std::string basename; |
187 ++count_non_core; | 199 // If there is a valid looking extension, use the base part of the |
188 } | 200 // name. If the only dot is the first byte (aka a dot file), treat |
| 201 // it as unique to avoid allowing a directory full of dot files |
| 202 // from accumulating. |
| 203 if (last_dot != std::string::npos && last_dot != 0) |
| 204 basename = filename.substr(0, last_dot); |
| 205 else |
| 206 basename = filename; |
| 207 basenames.insert(basename); |
189 | 208 |
190 if (count_core >= kMaxCrashDirectorySize || | 209 if (basenames.size() >= static_cast<size_t>(kMaxCrashDirectorySize)) { |
191 count_non_core >= kMaxCrashDirectorySize) { | |
192 logger_->LogWarning( | 210 logger_->LogWarning( |
193 "Crash directory %s already full with %d pending reports", | 211 "Crash directory %s already full with %d pending reports", |
194 crash_directory.value().c_str(), | 212 crash_directory.value().c_str(), |
195 kMaxCrashDirectorySize); | 213 kMaxCrashDirectorySize); |
196 full = true; | 214 full = true; |
197 break; | 215 break; |
198 } | 216 } |
199 } | 217 } |
200 closedir(dir); | 218 closedir(dir); |
201 return !full; | 219 return !full; |
202 } | 220 } |
| 221 |
| 222 bool CrashCollector::ReadKeyValueFile( |
| 223 const FilePath &path, |
| 224 const char separator, |
| 225 std::map<std::string, std::string> *dictionary) { |
| 226 std::string contents; |
| 227 if (!file_util::ReadFileToString(path, &contents)) { |
| 228 return false; |
| 229 } |
| 230 typedef std::vector<std::string> StringVector; |
| 231 StringVector lines; |
| 232 SplitString(contents, '\n', &lines); |
| 233 bool any_errors = false; |
| 234 for (StringVector::iterator line = lines.begin(); line != lines.end(); |
| 235 ++line) { |
| 236 // Allow empty strings. |
| 237 if (line->empty()) |
| 238 continue; |
| 239 StringVector sides; |
| 240 SplitString(*line, separator, &sides); |
| 241 if (sides.size() != 2) { |
| 242 any_errors = true; |
| 243 continue; |
| 244 } |
| 245 dictionary->insert(std::pair<std::string, std::string>(sides[0], sides[1])); |
| 246 } |
| 247 return !any_errors; |
| 248 } |
| 249 |
| 250 void CrashCollector::WriteCrashMetaData(const FilePath &meta_path, |
| 251 const std::string &exec_name) { |
| 252 std::map<std::string, std::string> contents; |
| 253 if (!ReadKeyValueFile(FilePath(std::string(kLsbRelease)), '=', &contents)) { |
| 254 logger_->LogError("Problem parsing %s", kLsbRelease); |
| 255 // Even though there was some failure, take as much as we could read. |
| 256 } |
| 257 std::string version("unknown"); |
| 258 std::map<std::string, std::string>::iterator i; |
| 259 if ((i = contents.find("CHROMEOS_RELEASE_VERSION")) != contents.end()) { |
| 260 version = i->second; |
| 261 } |
| 262 std::string meta_data = StringPrintf("exec_name=%s\n" |
| 263 "ver=%s\n" |
| 264 "done=1\n", |
| 265 exec_name.c_str(), |
| 266 version.c_str()); |
| 267 if (!file_util::WriteFile(meta_path, meta_data.c_str(), meta_data.size())) { |
| 268 logger_->LogError("Unable to write %s", meta_path.value().c_str()); |
| 269 } |
| 270 } |
OLD | NEW |