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

Side by Side Diff: tools/crashpad_database_util.cc

Issue 1022663002: Add crashpad_database_util and its man page (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address review feedback Created 5 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
« no previous file with comments | « tools/crashpad_database_util.ad ('k') | tools/generate_dump.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <errno.h>
16 #include <getopt.h>
17 #include <libgen.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <time.h>
23
24 #include <string>
25 #include <vector>
26
27 #include "base/basictypes.h"
28 #include "base/logging.h"
29 #include "base/files/file_path.h"
30 #include "base/memory/scoped_ptr.h"
31 #include "base/numerics/safe_conversions.h"
32 #include "client/crash_report_database.h"
33 #include "client/settings.h"
34 #include "tools/tool_support.h"
35 #include "util/misc/uuid.h"
36
37 namespace crashpad {
38 namespace {
39
40 void Usage(const std::string& me) {
41 fprintf(stderr,
42 "Usage: %s [OPTION]... PID\n"
43 "Operate on Crashpad crash report databases.\n"
44 "\n"
45 " -d, --database=PATH operate on the crash report database at PATH\ n"
46 " --show-client-id show the client ID\n"
47 " --show-uploads-enabled show whether uploads are enabled\n"
48 " --show-last-upload-attempt-time\n"
49 " show the last-upload-attempt time\n"
50 " --show-pending-reports show reports eligible for upload\n"
51 " --show-completed-reports show reports not eligible for upload\n"
52 " --show-all-report-info with --show-*-reports, show more information\ n"
53 " --show-report=UUID show report stored under UUID\n"
54 " --set-uploads-enabled=BOOL enable or disable uploads\n"
55 " --set-last-upload-attempt-time=TIME\n"
56 " set the last-upload-attempt time to TIME\n"
57 " --utc show and set UTC times instead of local\n"
58 " --help display this help and exit\n"
59 " --version output version information and exit\n",
60 me.c_str());
61 ToolSupport::UsageTail(me);
62 }
63
64 struct Options {
65 std::vector<UUID> show_reports;
66 const char* database;
67 const char* set_last_upload_attempt_time_string;
68 time_t set_last_upload_attempt_time;
69 bool show_client_id;
70 bool show_uploads_enabled;
71 bool show_last_upload_attempt_time;
72 bool show_pending_reports;
73 bool show_completed_reports;
74 bool show_all_report_info;
75 bool set_uploads_enabled;
76 bool has_set_uploads_enabled;
77 bool utc;
78 };
79
80 // Converts |string| to |boolean|, returning true if a conversion could be
81 // performed, and false without setting |boolean| if no conversion could be
82 // performed. Various string representations of a boolean are recognized
83 // case-insensitively.
84 bool StringToBool(const char* string, bool* boolean) {
85 const char* const kFalseWords[] = {
86 "0",
87 "false",
88 "no",
89 "off",
90 "disabled",
91 "clear",
92 };
93 const char* const kTrueWords[] = {
94 "1",
95 "true",
96 "yes",
97 "on",
98 "enabled",
99 "set",
100 };
101
102 for (size_t index = 0; index < arraysize(kFalseWords); ++index) {
103 if (strcasecmp(string, kFalseWords[index]) == 0) {
104 *boolean = false;
105 return true;
106 }
107 }
108
109 for (size_t index = 0; index < arraysize(kTrueWords); ++index) {
110 if (strcasecmp(string, kTrueWords[index]) == 0) {
111 *boolean = true;
112 return true;
113 }
114 }
115
116 return false;
117 }
118
119 // Converts |boolean| to a string, either "true" or "false".
120 std::string BoolToString(bool boolean) {
121 return std::string(boolean ? "true" : "false");
122 }
123
124 // Converts |string| to |time|, returning true if a conversion could be
125 // performed, and false without setting |boolean| if no conversion could be
126 // performed. Various time formats are recognized, including several string
127 // representations and a numeric time_t representation. The special string
128 // "never" is recognized as |string| and converts to a |time| value of 0. |utc|,
129 // when true, causes |string| to be interpreted as a UTC time rather than a
130 // local time when the time zone is ambiguous.
131 bool StringToTime(const char* string, time_t* time, bool utc) {
132 if (strcasecmp(string, "never") == 0) {
133 *time = 0;
134 return true;
135 }
136
137 const char* end = string + strlen(string);
138
139 const char* const kFormats[] = {
140 "%Y-%m-%d %H:%M:%S %Z",
141 "%Y-%m-%d %H:%M:%S",
142 "%+",
143 };
144
145 for (size_t index = 0; index < arraysize(kFormats); ++index) {
146 tm time_tm;
147 const char* strptime_result = strptime(string, kFormats[index], &time_tm);
148 if (strptime_result == end) {
149 if (utc) {
150 *time = timegm(&time_tm);
151 } else {
152 *time = timelocal(&time_tm);
153 }
154
155 return true;
156 }
157 }
158
159 char* end_result;
160 errno = 0;
161 long long strtoll_result = strtoll(string, &end_result, 0);
162 if (end_result == end && errno == 0 &&
163 base::IsValueInRangeForNumericType<time_t>(strtoll_result)) {
164 *time = strtoll_result;
165 return true;
166 }
167
168 return false;
169 }
170
171 // Converst |time_tt| to a string, and returns it. |utc| determines whether the
172 // converted time will reference local time or UTC. If |time_tt| is 0, the
173 // string "never" will be returned as a special case.
174 std::string TimeToString(time_t time_tt, bool utc) {
175 if (time_tt == 0) {
176 return std::string("never");
177 }
178
179 tm time_tm;
180 if (utc) {
181 gmtime_r(&time_tt, &time_tm);
182 } else {
183 localtime_r(&time_tt, &time_tm);
184 }
185
186 char string[64];
187 CHECK_NE(
188 strftime(string, arraysize(string), "%Y-%m-%d %H:%M:%S %Z", &time_tm),
189 0u);
190
191 return std::string(string);
192 }
193
194 // Shows information about a single |report|. |space_count| is the number of
195 // spaces to print before each line that is printed. |utc| determines whether
196 // times should be shown in UTC or the local time zone.
197 void ShowReport(const CrashReportDatabase::Report& report,
198 size_t space_count,
199 bool utc) {
200 std::string spaces(space_count, ' ');
201
202 printf("%sPath: %s\n", spaces.c_str(), report.file_path.value().c_str());
203 if (!report.id.empty()) {
204 printf("%sRemote ID: %s\n", spaces.c_str(), report.id.c_str());
205 }
206 printf("%sCreation time: %s\n",
207 spaces.c_str(),
208 TimeToString(report.creation_time, utc).c_str());
209 printf("%sUploaded: %s\n",
210 spaces.c_str(),
211 BoolToString(report.uploaded).c_str());
212 printf("%sLast upload attempt time: %s\n",
213 spaces.c_str(),
214 TimeToString(report.last_upload_attempt_time, utc).c_str());
215 printf("%sUpload attempts: %d\n", spaces.c_str(), report.upload_attempts);
216 }
217
218 // Shows information about a vector of |reports|. |space_count| is the number of
219 // spaces to print before each line that is printed. |options| will be consulted
220 // to determine whether to show expanded information
221 // (options.show_all_report_info) and what time zone to use when showing
222 // expanded information (options.utc).
223 void ShowReports(const std::vector<CrashReportDatabase::Report>& reports,
224 size_t space_count,
225 const Options& options) {
226 std::string spaces(space_count, ' ');
227 const char* colon = options.show_all_report_info ? ":" : "";
228
229 for (const CrashReportDatabase::Report& report : reports) {
230 printf("%s%s%s\n", spaces.c_str(), report.uuid.ToString().c_str(), colon);
231 if (options.show_all_report_info) {
232 ShowReport(report, space_count + 2, options.utc);
233 }
234 }
235 }
236
237 int DatabaseUtilMain(int argc, char* argv[]) {
238 const std::string me(basename(argv[0]));
239
240 enum OptionFlags {
241 // “Short” (single-character) options.
242 kOptionDatabase = 'd',
243
244 // Long options without short equivalents.
245 kOptionLastChar = 255,
246 kOptionShowClientID,
247 kOptionShowUploadsEnabled,
248 kOptionShowLastUploadAttemptTime,
249 kOptionShowPendingReports,
250 kOptionShowCompletedReports,
251 kOptionShowAllReportInfo,
252 kOptionShowReport,
253 kOptionSetUploadsEnabled,
254 kOptionSetLastUploadAttemptTime,
255 kOptionUTC,
256
257 // Standard options.
258 kOptionHelp = -2,
259 kOptionVersion = -3,
260 };
261
262 const option long_options[] = {
263 {"database", required_argument, nullptr, kOptionDatabase},
264 {"show-client-id", no_argument, nullptr, kOptionShowClientID},
265 {"show-uploads-enabled", no_argument, nullptr, kOptionShowUploadsEnabled},
266 {"show-last-upload-attempt-time",
267 no_argument,
268 nullptr,
269 kOptionShowLastUploadAttemptTime},
270 {"show-pending-reports", no_argument, nullptr, kOptionShowPendingReports},
271 {"show-completed-reports",
272 no_argument,
273 nullptr,
274 kOptionShowCompletedReports},
275 {"show-all-report-info", no_argument, nullptr, kOptionShowAllReportInfo},
276 {"show-report", required_argument, nullptr, kOptionShowReport},
277 {"set-uploads-enabled",
278 required_argument,
279 nullptr,
280 kOptionSetUploadsEnabled},
281 {"set-last-upload-attempt-time",
282 required_argument,
283 nullptr,
284 kOptionSetLastUploadAttemptTime},
285 {"utc", no_argument, nullptr, kOptionUTC},
286 {"help", no_argument, nullptr, kOptionHelp},
287 {"version", no_argument, nullptr, kOptionVersion},
288 {nullptr, 0, nullptr, 0},
289 };
290
291 Options options = {};
292
293 int opt;
294 while ((opt = getopt_long(argc, argv, "d:", long_options, nullptr)) != -1) {
295 switch (opt) {
296 case kOptionDatabase: {
297 options.database = optarg;
298 break;
299 }
300 case kOptionShowClientID: {
301 options.show_client_id = true;
302 break;
303 }
304 case kOptionShowUploadsEnabled: {
305 options.show_uploads_enabled = true;
306 break;
307 }
308 case kOptionShowLastUploadAttemptTime: {
309 options.show_last_upload_attempt_time = true;
310 break;
311 }
312 case kOptionShowPendingReports: {
313 options.show_pending_reports = true;
314 break;
315 }
316 case kOptionShowCompletedReports: {
317 options.show_completed_reports = true;
318 break;
319 }
320 case kOptionShowAllReportInfo: {
321 options.show_all_report_info = true;
322 break;
323 }
324 case kOptionShowReport: {
325 UUID uuid;
326 if (!uuid.InitializeFromString(optarg)) {
327 ToolSupport::UsageHint(me, "--show-report requires a UUID");
328 return EXIT_FAILURE;
329 }
330 options.show_reports.push_back(uuid);
331 break;
332 }
333 case kOptionSetUploadsEnabled: {
334 if (!StringToBool(optarg, &options.set_uploads_enabled)) {
335 ToolSupport::UsageHint(me, "--set-uploads-enabled requires a BOOL");
336 return EXIT_FAILURE;
337 }
338 options.has_set_uploads_enabled = true;
339 break;
340 }
341 case kOptionSetLastUploadAttemptTime: {
342 options.set_last_upload_attempt_time_string = optarg;
343 break;
344 }
345 case kOptionUTC: {
346 options.utc = true;
347 break;
348 }
349 case kOptionHelp: {
350 Usage(me);
351 return EXIT_SUCCESS;
352 }
353 case kOptionVersion: {
354 ToolSupport::Version(me);
355 return EXIT_SUCCESS;
356 }
357 default: {
358 ToolSupport::UsageHint(me, nullptr);
359 return EXIT_FAILURE;
360 }
361 }
362 }
363 argc -= optind;
364 argv += optind;
365
366 if (!options.database) {
367 ToolSupport::UsageHint(me, "--database is required");
368 return EXIT_FAILURE;
369 }
370
371 // This conversion couldn’t happen in the option-processing loop above because
372 // it depends on options.utc, which may have been set after
373 // options.set_last_upload_attempt_time_string.
374 if (options.set_last_upload_attempt_time_string) {
375 if (!StringToTime(options.set_last_upload_attempt_time_string,
376 &options.set_last_upload_attempt_time,
377 options.utc)) {
378 ToolSupport::UsageHint(me,
379 "--set-last-upload-attempt-time requires a TIME");
380 return EXIT_FAILURE;
381 }
382 }
383
384 const size_t show_operations = options.show_client_id +
385 options.show_uploads_enabled +
386 options.show_last_upload_attempt_time +
387 options.show_pending_reports +
388 options.show_completed_reports +
389 options.show_reports.size();
390 const size_t set_operations =
391 options.has_set_uploads_enabled +
392 (options.set_last_upload_attempt_time_string != nullptr);
393
394 if (show_operations + set_operations == 0) {
395 ToolSupport::UsageHint(me, "nothing to do");
396 return EXIT_FAILURE;
397 }
398
399 scoped_ptr<CrashReportDatabase> database(
400 CrashReportDatabase::Initialize(base::FilePath(options.database)));
401 if (!database) {
402 return EXIT_FAILURE;
403 }
404
405 Settings* settings = database->GetSettings();
406
407 // Handle the “show” options before the “set” options so that when they’re
408 // specified together, the “show” option reflects the initial state.
409
410 if (options.show_client_id) {
411 UUID client_id;
412 if (!settings->GetClientID(&client_id)) {
413 return EXIT_FAILURE;
414 }
415
416 const char* prefix = (show_operations > 1) ? "Client ID: " : "";
417
418 printf("%s%s\n", prefix, client_id.ToString().c_str());
419 }
420
421 if (options.show_uploads_enabled) {
422 bool uploads_enabled;
423 if (!settings->GetUploadsEnabled(&uploads_enabled)) {
424 return EXIT_FAILURE;
425 }
426
427 const char* prefix = (show_operations > 1) ? "Uploads enabled: " : "";
428
429 printf("%s%s\n", prefix, BoolToString(uploads_enabled).c_str());
430 }
431
432 if (options.show_last_upload_attempt_time) {
433 time_t last_upload_attempt_time;
434 if (!settings->GetLastUploadAttemptTime(&last_upload_attempt_time)) {
435 return EXIT_FAILURE;
436 }
437
438 const char* prefix =
439 (show_operations > 1) ? "Last upload attempt time: " : "";
440
441 printf("%s%s (%ld)\n",
442 prefix,
443 TimeToString(last_upload_attempt_time, options.utc).c_str(),
444 implicit_cast<long>(last_upload_attempt_time));
445 }
446
447 if (options.show_pending_reports) {
448 std::vector<CrashReportDatabase::Report> pending_reports;
449 if (database->GetPendingReports(&pending_reports) !=
450 CrashReportDatabase::kNoError) {
451 return EXIT_FAILURE;
452 }
453
454 if (show_operations > 1) {
455 printf("Pending reports:\n");
456 }
457
458 ShowReports(pending_reports, show_operations > 1 ? 2 : 0, options);
459 }
460
461 if (options.show_completed_reports) {
462 std::vector<CrashReportDatabase::Report> completed_reports;
463 if (database->GetCompletedReports(&completed_reports) !=
464 CrashReportDatabase::kNoError) {
465 return EXIT_FAILURE;
466 }
467
468 if (show_operations > 1) {
469 printf("Completed reports:\n");
470 }
471
472 ShowReports(completed_reports, show_operations > 1 ? 2 : 0, options);
473 }
474
475 for (const UUID& uuid : options.show_reports) {
476 CrashReportDatabase::Report report;
477 CrashReportDatabase::OperationStatus status =
478 database->LookUpCrashReport(uuid, &report);
479 if (status == CrashReportDatabase::kNoError) {
480 if (show_operations > 1) {
481 printf("Report %s:\n", uuid.ToString().c_str());
482 }
483 ShowReport(report, show_operations > 1 ? 2 : 0, options.utc);
484 } else if (status == CrashReportDatabase::kReportNotFound) {
485 // If only asked to do one thing, a failure to find the single requested
486 // report should result in a failure exit status.
487 if (show_operations + set_operations == 1) {
488 fprintf(stderr, "%s: Report not found\n", me.c_str());
489 return EXIT_FAILURE;
490 }
491 printf("Report %s not found\n", uuid.ToString().c_str());
492 } else {
493 return EXIT_FAILURE;
494 }
495 }
496
497 if (options.has_set_uploads_enabled &&
498 !settings->SetUploadsEnabled(options.set_uploads_enabled)) {
499 return EXIT_FAILURE;
500 }
501
502 if (options.set_last_upload_attempt_time_string &&
503 !settings->SetLastUploadAttemptTime(
504 options.set_last_upload_attempt_time)) {
505 return EXIT_FAILURE;
506 }
507
508 return EXIT_SUCCESS;
509 }
510
511 } // namespace
512 } // namespace crashpad
513
514 int main(int argc, char* argv[]) {
515 return crashpad::DatabaseUtilMain(argc, argv);
516 }
OLDNEW
« no previous file with comments | « tools/crashpad_database_util.ad ('k') | tools/generate_dump.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698