Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: crash_collector.cc

Issue 6517001: crash-reporter: Use standard logging and new libchromeos Process code (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/crash-reporter.git@master
Patch Set: More comments Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « crash_collector.h ('k') | crash_collector_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <fcntl.h> // For file creation modes. 8 #include <fcntl.h> // For file creation modes.
9 #include <pwd.h> // For struct passwd. 9 #include <pwd.h> // For struct passwd.
10 #include <sys/types.h> // for mode_t. 10 #include <sys/types.h> // for mode_t.
11 #include <sys/wait.h> // For waitpid. 11 #include <sys/wait.h> // For waitpid.
12 #include <unistd.h> // For execv and fork. 12 #include <unistd.h> // For execv and fork.
13 13
14 #include <set> 14 #include <set>
15 15
16 #include "base/eintr_wrapper.h" 16 #include "base/eintr_wrapper.h"
17 #include "base/file_util.h" 17 #include "base/file_util.h"
18 #include "base/logging.h" 18 #include "base/logging.h"
19 #include "base/string_util.h" 19 #include "base/string_util.h"
20 #include "crash-reporter/system_logging.h" 20 #include "chromeos/process.h"
21 21
22 static const char kDefaultUserName[] = "chronos"; 22 static const char kDefaultUserName[] = "chronos";
23 static const char kLsbRelease[] = "/etc/lsb-release"; 23 static const char kLsbRelease[] = "/etc/lsb-release";
24 static const char kShellPath[] = "/bin/sh"; 24 static const char kShellPath[] = "/bin/sh";
25 static const char kSystemCrashPath[] = "/var/spool/crash"; 25 static const char kSystemCrashPath[] = "/var/spool/crash";
26 static const char kUserCrashPath[] = "/home/chronos/user/crash"; 26 static const char kUserCrashPath[] = "/home/chronos/user/crash";
27 27
28 // Directory mode of the user crash spool directory. 28 // Directory mode of the user crash spool directory.
29 static const mode_t kUserCrashPathMode = 0755; 29 static const mode_t kUserCrashPathMode = 0755;
30 30
(...skipping 16 matching lines...) Expand all
47 CrashCollector::CrashCollector() 47 CrashCollector::CrashCollector()
48 : forced_crash_directory_(NULL), 48 : forced_crash_directory_(NULL),
49 lsb_release_(kLsbRelease) { 49 lsb_release_(kLsbRelease) {
50 } 50 }
51 51
52 CrashCollector::~CrashCollector() { 52 CrashCollector::~CrashCollector() {
53 } 53 }
54 54
55 void CrashCollector::Initialize( 55 void CrashCollector::Initialize(
56 CrashCollector::CountCrashFunction count_crash_function, 56 CrashCollector::CountCrashFunction count_crash_function,
57 CrashCollector::IsFeedbackAllowedFunction is_feedback_allowed_function, 57 CrashCollector::IsFeedbackAllowedFunction is_feedback_allowed_function) {
58 SystemLogging *logger) {
59 CHECK(count_crash_function != NULL); 58 CHECK(count_crash_function != NULL);
60 CHECK(is_feedback_allowed_function != NULL); 59 CHECK(is_feedback_allowed_function != NULL);
61 CHECK(logger != NULL);
62 60
63 count_crash_function_ = count_crash_function; 61 count_crash_function_ = count_crash_function;
64 is_feedback_allowed_function_ = is_feedback_allowed_function; 62 is_feedback_allowed_function_ = is_feedback_allowed_function;
65 logger_ = logger;
66 } 63 }
67 64
68 int CrashCollector::WriteNewFile(const FilePath &filename, 65 int CrashCollector::WriteNewFile(const FilePath &filename,
69 const char *data, 66 const char *data,
70 int size) { 67 int size) {
71 int fd = HANDLE_EINTR(open(filename.value().c_str(), 68 int fd = HANDLE_EINTR(open(filename.value().c_str(),
72 O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666)); 69 O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666));
73 if (fd < 0) { 70 if (fd < 0) {
74 return -1; 71 return -1;
75 } 72 }
76 73
77 int rv = file_util::WriteFileDescriptor(fd, data, size); 74 int rv = file_util::WriteFileDescriptor(fd, data, size);
78 HANDLE_EINTR(close(fd)); 75 HANDLE_EINTR(close(fd));
79 return rv; 76 return rv;
80 } 77 }
81 78
82 int CrashCollector::ForkExecAndPipe(std::vector<const char *> &arguments,
83 const char *output_file) {
84 // Copy off a writeable version of arguments.
85 scoped_array<char*> argv(new char *[arguments.size() + 1]);
86 int total_args_size = 0;
87 for (size_t i = 0; i < arguments.size(); ++i) {
88 if (arguments[i] == NULL) {
89 logger_->LogError("Bad parameter");
90 return -1;
91 }
92 total_args_size += strlen(arguments[i]) + 1;
93 }
94 scoped_array<char> buffer(new char[total_args_size]);
95 char *buffer_pointer = &buffer[0];
96
97 for (size_t i = 0; i < arguments.size(); ++i) {
98 argv[i] = buffer_pointer;
99 strcpy(buffer_pointer, arguments[i]);
100 buffer_pointer += strlen(arguments[i]);
101 *buffer_pointer = '\0';
102 ++buffer_pointer;
103 }
104 argv[arguments.size()] = NULL;
105
106 int pid = fork();
107 if (pid < 0) {
108 logger_->LogError("Fork failed: %d", errno);
109 return -1;
110 }
111
112 if (pid == 0) {
113 int output_handle = HANDLE_EINTR(
114 open(output_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666));
115 if (output_handle < 0) {
116 logger_->LogError("Could not create %s: %d", output_file, errno);
117 // Avoid exit() to avoid atexit handlers from parent.
118 _exit(127);
119 }
120 dup2(output_handle, 1);
121 dup2(output_handle, 2);
122 execv(argv[0], &argv[0]);
123 logger_->LogError("Exec failed: %d", errno);
124 _exit(127);
125 }
126
127 int status = 0;
128 if (HANDLE_EINTR(waitpid(pid, &status, 0)) < 0) {
129 logger_->LogError("Problem waiting for pid: %d", errno);
130 return -1;
131 }
132 if (!WIFEXITED(status)) {
133 logger_->LogError("Process did not exit normally: %d", status);
134 return -1;
135 }
136 return WEXITSTATUS(status);
137 }
138
139 std::string CrashCollector::Sanitize(const std::string &name) { 79 std::string CrashCollector::Sanitize(const std::string &name) {
140 std::string result = name; 80 std::string result = name;
141 for (size_t i = 0; i < name.size(); ++i) { 81 for (size_t i = 0; i < name.size(); ++i) {
142 if (!isalnum(result[i]) && result[i] != '_') 82 if (!isalnum(result[i]) && result[i] != '_')
143 result[i] = '_'; 83 result[i] = '_';
144 } 84 }
145 return result; 85 return result;
146 } 86 }
147 87
148 std::string CrashCollector::FormatDumpBasename(const std::string &exec_name, 88 std::string CrashCollector::FormatDumpBasename(const std::string &exec_name,
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 132
193 bool CrashCollector::GetUserInfoFromName(const std::string &name, 133 bool CrashCollector::GetUserInfoFromName(const std::string &name,
194 uid_t *uid, 134 uid_t *uid,
195 gid_t *gid) { 135 gid_t *gid) {
196 char storage[256]; 136 char storage[256];
197 struct passwd passwd_storage; 137 struct passwd passwd_storage;
198 struct passwd *passwd_result = NULL; 138 struct passwd *passwd_result = NULL;
199 139
200 if (getpwnam_r(name.c_str(), &passwd_storage, storage, sizeof(storage), 140 if (getpwnam_r(name.c_str(), &passwd_storage, storage, sizeof(storage),
201 &passwd_result) != 0 || passwd_result == NULL) { 141 &passwd_result) != 0 || passwd_result == NULL) {
202 logger_->LogError("Cannot find user named %s", name.c_str()); 142 LOG(ERROR) << "Cannot find user named " << name;
203 return false; 143 return false;
204 } 144 }
205 145
206 *uid = passwd_result->pw_uid; 146 *uid = passwd_result->pw_uid;
207 *gid = passwd_result->pw_gid; 147 *gid = passwd_result->pw_gid;
208 return true; 148 return true;
209 } 149 }
210 150
211 bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid, 151 bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid,
212 FilePath *crash_directory, 152 FilePath *crash_directory,
213 bool *out_of_capacity) { 153 bool *out_of_capacity) {
214 uid_t default_user_id; 154 uid_t default_user_id;
215 gid_t default_user_group; 155 gid_t default_user_group;
216 156
217 if (out_of_capacity != NULL) *out_of_capacity = false; 157 if (out_of_capacity != NULL) *out_of_capacity = false;
218 158
219 // For testing. 159 // For testing.
220 if (forced_crash_directory_ != NULL) { 160 if (forced_crash_directory_ != NULL) {
221 *crash_directory = FilePath(forced_crash_directory_); 161 *crash_directory = FilePath(forced_crash_directory_);
222 return true; 162 return true;
223 } 163 }
224 164
225 if (!GetUserInfoFromName(kDefaultUserName, 165 if (!GetUserInfoFromName(kDefaultUserName,
226 &default_user_id, 166 &default_user_id,
227 &default_user_group)) { 167 &default_user_group)) {
228 logger_->LogError("Could not find default user info"); 168 LOG(ERROR) << "Could not find default user info";
229 return false; 169 return false;
230 } 170 }
231 mode_t directory_mode; 171 mode_t directory_mode;
232 uid_t directory_owner; 172 uid_t directory_owner;
233 gid_t directory_group; 173 gid_t directory_group;
234 *crash_directory = 174 *crash_directory =
235 GetCrashDirectoryInfo(euid, 175 GetCrashDirectoryInfo(euid,
236 default_user_id, 176 default_user_id,
237 default_user_group, 177 default_user_group,
238 &directory_mode, 178 &directory_mode,
239 &directory_owner, 179 &directory_owner,
240 &directory_group); 180 &directory_group);
241 181
242 if (!file_util::PathExists(*crash_directory)) { 182 if (!file_util::PathExists(*crash_directory)) {
243 // Create the spool directory with the appropriate mode (regardless of 183 // Create the spool directory with the appropriate mode (regardless of
244 // umask) and ownership. 184 // umask) and ownership.
245 mode_t old_mask = umask(0); 185 mode_t old_mask = umask(0);
246 if (mkdir(crash_directory->value().c_str(), directory_mode) < 0 || 186 if (mkdir(crash_directory->value().c_str(), directory_mode) < 0 ||
247 chown(crash_directory->value().c_str(), 187 chown(crash_directory->value().c_str(),
248 directory_owner, 188 directory_owner,
249 directory_group) < 0) { 189 directory_group) < 0) {
250 logger_->LogError("Unable to create appropriate crash directory"); 190 LOG(ERROR) << "Unable to create appropriate crash directory";
251 return false; 191 return false;
252 } 192 }
253 umask(old_mask); 193 umask(old_mask);
254 } 194 }
255 195
256 if (!file_util::PathExists(*crash_directory)) { 196 if (!file_util::PathExists(*crash_directory)) {
257 logger_->LogError("Unable to create crash directory %s", 197 LOG(ERROR) << "Unable to create crash directory "
258 crash_directory->value().c_str()); 198 << crash_directory->value().c_str();
259 return false; 199 return false;
260 } 200 }
261 201
262 if (!CheckHasCapacity(*crash_directory)) { 202 if (!CheckHasCapacity(*crash_directory)) {
263 if (out_of_capacity != NULL) *out_of_capacity = true; 203 if (out_of_capacity != NULL) *out_of_capacity = true;
264 return false; 204 return false;
265 } 205 }
266 206
267 return true; 207 return true;
268 } 208 }
(...skipping 21 matching lines...) Expand all
290 // name. If the only dot is the first byte (aka a dot file), treat 230 // name. If the only dot is the first byte (aka a dot file), treat
291 // it as unique to avoid allowing a directory full of dot files 231 // it as unique to avoid allowing a directory full of dot files
292 // from accumulating. 232 // from accumulating.
293 if (last_dot != std::string::npos && last_dot != 0) 233 if (last_dot != std::string::npos && last_dot != 0)
294 basename = filename.substr(0, last_dot); 234 basename = filename.substr(0, last_dot);
295 else 235 else
296 basename = filename; 236 basename = filename;
297 basenames.insert(basename); 237 basenames.insert(basename);
298 238
299 if (basenames.size() >= static_cast<size_t>(kMaxCrashDirectorySize)) { 239 if (basenames.size() >= static_cast<size_t>(kMaxCrashDirectorySize)) {
300 logger_->LogWarning( 240 LOG(WARNING) << "Crash directory " << crash_directory.value()
301 "Crash directory %s already full with %d pending reports", 241 << " already full with " << kMaxCrashDirectorySize
302 crash_directory.value().c_str(), 242 << " pending reports";
303 kMaxCrashDirectorySize);
304 full = true; 243 full = true;
305 break; 244 break;
306 } 245 }
307 } 246 }
308 closedir(dir); 247 closedir(dir);
309 return !full; 248 return !full;
310 } 249 }
311 250
312 bool CrashCollector::IsCommentLine(const std::string &line) { 251 bool CrashCollector::IsCommentLine(const std::string &line) {
313 size_t found = line.find_first_not_of(" "); 252 size_t found = line.find_first_not_of(" ");
(...skipping 29 matching lines...) Expand all
343 dictionary->insert(std::pair<std::string, std::string>(sides[0], sides[1])); 282 dictionary->insert(std::pair<std::string, std::string>(sides[0], sides[1]));
344 } 283 }
345 return !any_errors; 284 return !any_errors;
346 } 285 }
347 286
348 bool CrashCollector::GetLogContents(const FilePath &config_path, 287 bool CrashCollector::GetLogContents(const FilePath &config_path,
349 const std::string &exec_name, 288 const std::string &exec_name,
350 const FilePath &output_file) { 289 const FilePath &output_file) {
351 std::map<std::string, std::string> log_commands; 290 std::map<std::string, std::string> log_commands;
352 if (!ReadKeyValueFile(config_path, ':', &log_commands)) { 291 if (!ReadKeyValueFile(config_path, ':', &log_commands)) {
353 logger_->LogInfo("Unable to read log configuration file %s", 292 LOG(INFO) << "Unable to read log configuration file "
354 config_path.value().c_str()); 293 << config_path.value();
355 return false; 294 return false;
356 } 295 }
357 296
358 if (log_commands.find(exec_name) == log_commands.end()) 297 if (log_commands.find(exec_name) == log_commands.end())
359 return false; 298 return false;
360 299
361 std::vector<const char *> command; 300 chromeos::ProcessImpl diag_process;
362 command.push_back(kShellPath); 301 diag_process.AddArg(kShellPath);
363 command.push_back("-c");
364 std::string shell_command = log_commands[exec_name]; 302 std::string shell_command = log_commands[exec_name];
365 command.push_back(shell_command.c_str()); 303 diag_process.AddStringOption("-c", shell_command);
304 diag_process.RedirectOutput(output_file.value());
366 305
367 int fork_result = ForkExecAndPipe(command, output_file.value().c_str()); 306 int result = diag_process.Run();
368 if (fork_result != 0) { 307 if (result != 0) {
369 logger_->LogInfo("Running shell command %s failed with: %d", 308 LOG(INFO) << "Running shell command " << shell_command << "failed with: "
370 shell_command.c_str(), fork_result); 309 << result;
371 return false; 310 return false;
372 } 311 }
373 return true; 312 return true;
374 } 313 }
375 314
376 void CrashCollector::AddCrashMetaData(const std::string &key, 315 void CrashCollector::AddCrashMetaData(const std::string &key,
377 const std::string &value) { 316 const std::string &value) {
378 extra_metadata_.append(StringPrintf("%s=%s\n", key.c_str(), value.c_str())); 317 extra_metadata_.append(StringPrintf("%s=%s\n", key.c_str(), value.c_str()));
379 } 318 }
380 319
381 void CrashCollector::WriteCrashMetaData(const FilePath &meta_path, 320 void CrashCollector::WriteCrashMetaData(const FilePath &meta_path,
382 const std::string &exec_name, 321 const std::string &exec_name,
383 const std::string &payload_path) { 322 const std::string &payload_path) {
384 std::map<std::string, std::string> contents; 323 std::map<std::string, std::string> contents;
385 if (!ReadKeyValueFile(FilePath(std::string(lsb_release_)), '=', &contents)) { 324 if (!ReadKeyValueFile(FilePath(std::string(lsb_release_)), '=', &contents)) {
386 logger_->LogError("Problem parsing %s", lsb_release_); 325 LOG(ERROR) << "Problem parsing " << lsb_release_;
387 // Even though there was some failure, take as much as we could read. 326 // Even though there was some failure, take as much as we could read.
388 } 327 }
389 std::string version("unknown"); 328 std::string version("unknown");
390 std::map<std::string, std::string>::iterator i; 329 std::map<std::string, std::string>::iterator i;
391 if ((i = contents.find("CHROMEOS_RELEASE_VERSION")) != contents.end()) { 330 if ((i = contents.find("CHROMEOS_RELEASE_VERSION")) != contents.end()) {
392 version = i->second; 331 version = i->second;
393 } 332 }
394 int64 payload_size = -1; 333 int64 payload_size = -1;
395 file_util::GetFileSize(FilePath(payload_path), &payload_size); 334 file_util::GetFileSize(FilePath(payload_path), &payload_size);
396 std::string meta_data = StringPrintf("%sexec_name=%s\n" 335 std::string meta_data = StringPrintf("%sexec_name=%s\n"
397 "ver=%s\n" 336 "ver=%s\n"
398 "payload=%s\n" 337 "payload=%s\n"
399 "payload_size=%lld\n" 338 "payload_size=%lld\n"
400 "done=1\n", 339 "done=1\n",
401 extra_metadata_.c_str(), 340 extra_metadata_.c_str(),
402 exec_name.c_str(), 341 exec_name.c_str(),
403 version.c_str(), 342 version.c_str(),
404 payload_path.c_str(), 343 payload_path.c_str(),
405 payload_size); 344 payload_size);
406 // We must use WriteNewFile instead of file_util::WriteFile as we 345 // We must use WriteNewFile instead of file_util::WriteFile as we
407 // do not want to write with root access to a symlink that an attacker 346 // do not want to write with root access to a symlink that an attacker
408 // might have created. 347 // might have created.
409 if (WriteNewFile(meta_path, meta_data.c_str(), meta_data.size()) < 0) { 348 if (WriteNewFile(meta_path, meta_data.c_str(), meta_data.size()) < 0) {
410 logger_->LogError("Unable to write %s", meta_path.value().c_str()); 349 LOG(ERROR) << "Unable to write " << meta_path.value();
411 } 350 }
412 } 351 }
OLDNEW
« no previous file with comments | « crash_collector.h ('k') | crash_collector_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698