diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/linux_crash_logger/files.lst | 2 | ||||
-rw-r--r-- | linden/indra/linux_crash_logger/linux_crash_logger.cpp | 538 | ||||
-rw-r--r-- | linden/indra/linux_crash_logger/llcrashloggerlinux.cpp | 140 | ||||
-rw-r--r-- | linden/indra/linux_crash_logger/llcrashloggerlinux.h | 49 |
4 files changed, 197 insertions, 532 deletions
diff --git a/linden/indra/linux_crash_logger/files.lst b/linden/indra/linux_crash_logger/files.lst index 8bf99b0..5c8b9a2 100644 --- a/linden/indra/linux_crash_logger/files.lst +++ b/linden/indra/linux_crash_logger/files.lst | |||
@@ -1 +1,3 @@ | |||
1 | llcrashlogger/llcrashlogger.cpp | ||
1 | linux_crash_logger/linux_crash_logger.cpp | 2 | linux_crash_logger/linux_crash_logger.cpp |
3 | linux_crash_logger/llcrashloggerlinux.cpp | ||
diff --git a/linden/indra/linux_crash_logger/linux_crash_logger.cpp b/linden/indra/linux_crash_logger/linux_crash_logger.cpp index e75a317..5310093 100644 --- a/linden/indra/linux_crash_logger/linux_crash_logger.cpp +++ b/linden/indra/linux_crash_logger/linux_crash_logger.cpp | |||
@@ -29,542 +29,16 @@ | |||
29 | * $/LicenseInfo$ | 29 | * $/LicenseInfo$ |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include "linden_common.h" | 32 | #include "llcrashloggerlinux.h" |
33 | |||
34 | #include <sys/types.h> | ||
35 | #include <sys/stat.h> | ||
36 | #include <unistd.h> | ||
37 | |||
38 | #include <curl/curl.h> | ||
39 | |||
40 | #if LL_GTK | ||
41 | # include "gtk/gtk.h" | ||
42 | #endif // LL_GTK | ||
43 | |||
44 | #include "indra_constants.h" // CRASH_BEHAVIOR_ASK | ||
45 | #include "llerror.h" | ||
46 | #include "lltimer.h" | ||
47 | #include "lldir.h" | ||
48 | |||
49 | #include "llstring.h" | ||
50 | |||
51 | |||
52 | // These need to be localized. | ||
53 | static const char dialog_text[] = | ||
54 | "Second Life appears to have crashed.\n" | ||
55 | "This crash reporter collects information about your computer's hardware, operating system, and some Second Life logs, which are used for debugging purposes only.\n" | ||
56 | "Sending crash reports is the best way to help us improve the quality of Second Life.\n" | ||
57 | "If you continue to experience this problem, please try:\n" | ||
58 | "- Contacting support by visiting http://www.secondlife.com/support\n" | ||
59 | "\n" | ||
60 | "Send crash report?"; | ||
61 | |||
62 | static const char dialog_title[] = | ||
63 | "Second Life Crash Logger"; | ||
64 | |||
65 | |||
66 | class LLFileEncoder | ||
67 | { | ||
68 | public: | ||
69 | LLFileEncoder(const char *formname, const char *filename, bool isCrashLog = false); | ||
70 | |||
71 | BOOL isValid() const { return mIsValid; } | ||
72 | LLString encodeURL(const S32 max_length = 0); | ||
73 | public: | ||
74 | BOOL mIsValid; | ||
75 | LLString mFilename; | ||
76 | LLString mFormname; | ||
77 | LLString mBuf; | ||
78 | }; | ||
79 | |||
80 | LLString encode_string(const char *formname, const LLString &str); | ||
81 | |||
82 | LLString gServerResponse; | ||
83 | BOOL gSendReport = FALSE; | ||
84 | LLString gUserserver; | ||
85 | LLString gUserText; | ||
86 | BOOL gCrashInPreviousExec = FALSE; | ||
87 | time_t gLaunchTime; | ||
88 | |||
89 | static size_t curl_download_callback(void *data, size_t size, size_t nmemb, | ||
90 | void *user_data) | ||
91 | { | ||
92 | S32 bytes = size * nmemb; | ||
93 | char *cdata = (char *) data; | ||
94 | for (int i =0; i < bytes; i += 1) | ||
95 | { | ||
96 | gServerResponse += (cdata[i]); | ||
97 | } | ||
98 | return bytes; | ||
99 | } | ||
100 | |||
101 | #if LL_GTK | ||
102 | static void response_callback (GtkDialog *dialog, | ||
103 | gint arg1, | ||
104 | gpointer user_data) | ||
105 | { | ||
106 | gint *response = (gint*)user_data; | ||
107 | *response = arg1; | ||
108 | gtk_widget_destroy(GTK_WIDGET(dialog)); | ||
109 | gtk_main_quit(); | ||
110 | } | ||
111 | #endif // LL_GTK | ||
112 | |||
113 | static BOOL do_ask_dialog(void) | ||
114 | { | ||
115 | #if LL_GTK | ||
116 | gtk_disable_setlocale(); | ||
117 | if (!gtk_init_check(NULL, NULL)) { | ||
118 | llinfos << "Could not initialize GTK for 'ask to send crash report' dialog; not sending report." << llendl; | ||
119 | return FALSE; | ||
120 | } | ||
121 | |||
122 | GtkWidget *win = NULL; | ||
123 | GtkDialogFlags flags = GTK_DIALOG_MODAL; | ||
124 | GtkMessageType messagetype = GTK_MESSAGE_QUESTION; | ||
125 | GtkButtonsType buttons = GTK_BUTTONS_YES_NO; | ||
126 | gint response = GTK_RESPONSE_NONE; | ||
127 | |||
128 | win = gtk_message_dialog_new(NULL, | ||
129 | flags, messagetype, buttons, | ||
130 | dialog_text); | ||
131 | gtk_window_set_type_hint(GTK_WINDOW(win), | ||
132 | GDK_WINDOW_TYPE_HINT_DIALOG); | ||
133 | gtk_window_set_title(GTK_WINDOW(win), dialog_title); | ||
134 | g_signal_connect (win, | ||
135 | "response", | ||
136 | G_CALLBACK (response_callback), | ||
137 | &response); | ||
138 | gtk_widget_show_all (win); | ||
139 | gtk_main(); | ||
140 | |||
141 | return (GTK_RESPONSE_OK == response || | ||
142 | GTK_RESPONSE_YES == response || | ||
143 | GTK_RESPONSE_APPLY == response); | ||
144 | #else | ||
145 | return FALSE; | ||
146 | #endif // LL_GTK | ||
147 | } | ||
148 | |||
149 | 33 | ||
150 | int main(int argc, char **argv) | 34 | int main(int argc, char **argv) |
151 | { | 35 | { |
152 | const S32 BT_MAX_SIZE = 100000; // Maximum size to transmit of the backtrace file | 36 | LLCrashLoggerLinux app; |
153 | const S32 SL_MAX_SIZE = 100000; // Maximum size of the Second Life log file. | 37 | app.parseCommandOptions(argc, argv); |
154 | int i; | 38 | app.init(); |
155 | S32 crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND; | 39 | app.mainLoop(); |
156 | 40 | app.cleanup(); | |
157 | time(&gLaunchTime); | ||
158 | |||
159 | llinfos << "Starting Second Life Viewer Crash Reporter" << llendl; | ||
160 | |||
161 | for(i=1; i<argc; i++) | ||
162 | { | ||
163 | if(!strcmp(argv[i], "-dialog")) | ||
164 | { | ||
165 | llinfos << "Show the user dialog" << llendl; | ||
166 | crash_behavior = CRASH_BEHAVIOR_ASK; | ||
167 | } | ||
168 | if(!strcmp(argv[i], "-previous")) | ||
169 | { | ||
170 | gCrashInPreviousExec = TRUE; | ||
171 | } | ||
172 | if(!strcmp(argv[i], "-user")) | ||
173 | { | ||
174 | if ((i + 1) < argc) | ||
175 | { | ||
176 | i++; | ||
177 | gUserserver = argv[i]; | ||
178 | llinfos << "Got userserver " << gUserserver << llendl; | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | |||
183 | if( gCrashInPreviousExec ) | ||
184 | { | ||
185 | llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl; | ||
186 | } | ||
187 | |||
188 | if(!gCrashInPreviousExec) | ||
189 | { | ||
190 | // Wait a while to let the crashed client finish exiting, | ||
191 | // freeing up the screen/etc. | ||
192 | sleep(5); | ||
193 | } | ||
194 | |||
195 | // *FIX: do some dialog stuff here? | ||
196 | if (CRASH_BEHAVIOR_ALWAYS_SEND == crash_behavior) | ||
197 | { | ||
198 | gSendReport = TRUE; | ||
199 | } | ||
200 | else if (CRASH_BEHAVIOR_ASK == crash_behavior) | ||
201 | { | ||
202 | gSendReport = do_ask_dialog(); | ||
203 | } | ||
204 | |||
205 | if(!gSendReport) | ||
206 | { | ||
207 | // Only send the report if the user agreed to it. | ||
208 | llinfos << "User cancelled, not sending report" << llendl; | ||
209 | |||
210 | return(0); | ||
211 | } | ||
212 | |||
213 | // We assume that all the logs we're looking for reside on the current drive | ||
214 | gDirUtilp->initAppDirs("SecondLife"); | ||
215 | |||
216 | // Lots of silly variable, replicated for each log file. | ||
217 | LLString db_file_name; | ||
218 | LLString sl_file_name; | ||
219 | LLString bt_file_name; // stack_trace.log file | ||
220 | LLString st_file_name; // stats.log file | ||
221 | LLString si_file_name; // settings.xml file | ||
222 | |||
223 | LLFileEncoder *db_filep = NULL; | ||
224 | LLFileEncoder *sl_filep = NULL; | ||
225 | LLFileEncoder *st_filep = NULL; | ||
226 | LLFileEncoder *bt_filep = NULL; | ||
227 | LLFileEncoder *si_filep = NULL; | ||
228 | |||
229 | /////////////////////////////////// | ||
230 | // | ||
231 | // We do the parsing for the debug_info file first, as that will | ||
232 | // give us the location of the SecondLife.log file. | ||
233 | // | ||
234 | |||
235 | // Figure out the filename of the debug log | ||
236 | db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log").c_str(); | ||
237 | db_filep = new LLFileEncoder("DB", db_file_name.c_str()); | ||
238 | |||
239 | // Get the filename of the SecondLife.log file | ||
240 | // *NOTE: These buffer sizes are hardcoded into a scanf() below. | ||
241 | char tmp_sl_name[LL_MAX_PATH]; | ||
242 | tmp_sl_name[0] = '\0'; | ||
243 | char tmp_space[256]; | ||
244 | tmp_space[0] = '\0'; | ||
245 | |||
246 | // Look for it in the debug_info.log file | ||
247 | if (db_filep->isValid()) | ||
248 | { | ||
249 | // This was originally scanning for "SL Log: %[^\r\n]", which happily skipped to the next line | ||
250 | // on debug logs (which don't have anything after "SL Log:" and tried to open a nonsensical filename. | ||
251 | sscanf(db_filep->mBuf.c_str(), "SL Log:%255[ ]%1023[^\r\n]", tmp_space, tmp_sl_name); | ||
252 | } | ||
253 | else | ||
254 | { | ||
255 | delete db_filep; | ||
256 | db_filep = NULL; | ||
257 | } | ||
258 | |||
259 | // If we actually have a legitimate file name, use it. | ||
260 | if (gCrashInPreviousExec) | ||
261 | { | ||
262 | // If we froze, the crash log this time around isn't useful. | ||
263 | // Use the old one. | ||
264 | sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); | ||
265 | } | ||
266 | else if (tmp_sl_name[0]) | ||
267 | { | ||
268 | sl_file_name = tmp_sl_name; | ||
269 | llinfos << "Using log file from debug log: " << sl_file_name << llendl; | ||
270 | } | ||
271 | else | ||
272 | { | ||
273 | // Figure out the filename of the second life log | ||
274 | sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log").c_str(); | ||
275 | } | ||
276 | |||
277 | // Now we get the SecondLife.log file if it's there, and recent enough... | ||
278 | sl_filep = new LLFileEncoder("SL", sl_file_name.c_str()); | ||
279 | if (!sl_filep->isValid()) | ||
280 | { | ||
281 | delete sl_filep; | ||
282 | sl_filep = NULL; | ||
283 | } | ||
284 | |||
285 | st_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log").c_str(); | ||
286 | st_filep = new LLFileEncoder("ST", st_file_name.c_str()); | ||
287 | if (!st_filep->isValid()) | ||
288 | { | ||
289 | delete st_filep; | ||
290 | st_filep = NULL; | ||
291 | } | ||
292 | |||
293 | si_file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml").c_str(); | ||
294 | si_filep = new LLFileEncoder("SI", si_file_name.c_str()); | ||
295 | if (!si_filep->isValid()) | ||
296 | { | ||
297 | delete si_filep; | ||
298 | si_filep = NULL; | ||
299 | } | ||
300 | |||
301 | // encode this as if it were a 'Dr Watson' plain-text backtrace | ||
302 | bt_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log").c_str(); | ||
303 | bt_filep = new LLFileEncoder("DW", bt_file_name.c_str()); | ||
304 | if (!bt_filep->isValid()) | ||
305 | { | ||
306 | delete bt_filep; | ||
307 | bt_filep = NULL; | ||
308 | } | ||
309 | |||
310 | LLString post_data; | ||
311 | LLString tmp_url_buf; | ||
312 | |||
313 | // Append the userserver | ||
314 | tmp_url_buf = encode_string("USER", gUserserver); | ||
315 | post_data += tmp_url_buf; | ||
316 | llinfos << "PostData:" << post_data << llendl; | ||
317 | |||
318 | if (gCrashInPreviousExec) | ||
319 | { | ||
320 | post_data.append("&"); | ||
321 | tmp_url_buf = encode_string("EF", "Y"); | ||
322 | post_data += tmp_url_buf; | ||
323 | } | ||
324 | |||
325 | if (db_filep) | ||
326 | { | ||
327 | post_data.append("&"); | ||
328 | tmp_url_buf = db_filep->encodeURL(); | ||
329 | post_data += tmp_url_buf; | ||
330 | llinfos << "Sending DB log file" << llendl; | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | llinfos << "Not sending DB log file" << llendl; | ||
335 | } | ||
336 | |||
337 | if (sl_filep) | ||
338 | { | ||
339 | post_data.append("&"); | ||
340 | tmp_url_buf = sl_filep->encodeURL(SL_MAX_SIZE); | ||
341 | post_data += tmp_url_buf; | ||
342 | llinfos << "Sending SL log file" << llendl; | ||
343 | } | ||
344 | else | ||
345 | { | ||
346 | llinfos << "Not sending SL log file" << llendl; | ||
347 | } | ||
348 | |||
349 | if (st_filep) | ||
350 | { | ||
351 | post_data.append("&"); | ||
352 | tmp_url_buf = st_filep->encodeURL(SL_MAX_SIZE); | ||
353 | post_data += tmp_url_buf; | ||
354 | llinfos << "Sending stats log file" << llendl; | ||
355 | } | ||
356 | else | ||
357 | { | ||
358 | llinfos << "Not sending stats log file" << llendl; | ||
359 | } | ||
360 | |||
361 | if (bt_filep) | ||
362 | { | ||
363 | post_data.append("&"); | ||
364 | tmp_url_buf = bt_filep->encodeURL(BT_MAX_SIZE); | ||
365 | post_data += tmp_url_buf; | ||
366 | llinfos << "Sending crash log file" << llendl; | ||
367 | } | ||
368 | else | ||
369 | { | ||
370 | llinfos << "Not sending crash log file" << llendl; | ||
371 | } | ||
372 | |||
373 | if (si_filep) | ||
374 | { | ||
375 | post_data.append("&"); | ||
376 | tmp_url_buf = si_filep->encodeURL(); | ||
377 | post_data += tmp_url_buf; | ||
378 | llinfos << "Sending settings log file" << llendl; | ||
379 | } | ||
380 | else | ||
381 | { | ||
382 | llinfos << "Not sending settings.xml file" << llendl; | ||
383 | } | ||
384 | |||
385 | if (gUserText.size()) | ||
386 | { | ||
387 | post_data.append("&"); | ||
388 | tmp_url_buf = encode_string("UN", gUserText); | ||
389 | post_data += tmp_url_buf; | ||
390 | } | ||
391 | |||
392 | delete db_filep; | ||
393 | db_filep = NULL; | ||
394 | delete sl_filep; | ||
395 | sl_filep = NULL; | ||
396 | delete bt_filep; | ||
397 | bt_filep = NULL; | ||
398 | |||
399 | // Debugging spam | ||
400 | #if 0 | ||
401 | printf("Crash report post data:\n--------\n"); | ||
402 | printf("%s", post_data.getString()); | ||
403 | printf("\n--------\n"); | ||
404 | #endif | ||
405 | |||
406 | // Send the report. Yes, it's this easy. | ||
407 | { | ||
408 | CURL *curl = curl_easy_init(); | ||
409 | |||
410 | curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); | ||
411 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback); | ||
412 | curl_easy_setopt(curl, CURLOPT_POST, 1); | ||
413 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data.c_str()); | ||
414 | curl_easy_setopt(curl, CURLOPT_URL, "http://EXAMPLE.com/cgi-bin/viewer_crash_reporter2"); | ||
415 | |||
416 | llinfos << "Connecting to crash report server" << llendl; | ||
417 | CURLcode result = curl_easy_perform(curl); | ||
418 | |||
419 | curl_easy_cleanup(curl); | ||
420 | |||
421 | if(result != CURLE_OK) | ||
422 | { | ||
423 | llinfos << "Couldn't talk to crash report server" << llendl; | ||
424 | } | ||
425 | else | ||
426 | { | ||
427 | llinfos << "Response from crash report server:" << llendl; | ||
428 | llinfos << gServerResponse << llendl; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | return 0; | 41 | return 0; |
433 | } | 42 | } |
434 | 43 | ||
435 | LLFileEncoder::LLFileEncoder(const char *form_name, const char *filename, bool isCrashLog) | ||
436 | { | ||
437 | mFormname = form_name; | ||
438 | mFilename = filename; | ||
439 | mIsValid = FALSE; | ||
440 | |||
441 | int res; | ||
442 | |||
443 | struct stat stat_data; | ||
444 | res = stat(mFilename.c_str(), &stat_data); | ||
445 | if (res) | ||
446 | { | ||
447 | llwarns << "File " << mFilename << " is missing!" << llendl; | ||
448 | return; | ||
449 | } | ||
450 | else | ||
451 | { | ||
452 | // Debugging spam | ||
453 | // llinfos << "File " << mFilename << " is present..." << llendl; | ||
454 | |||
455 | if(!gCrashInPreviousExec && isCrashLog) | ||
456 | { | ||
457 | // Make sure the file isn't too old. | ||
458 | double age = difftime(gLaunchTime, stat_data.st_mtim.tv_sec); | ||
459 | |||
460 | // llinfos << "age is " << age << llendl; | ||
461 | 44 | ||
462 | if(age > 60.0) | ||
463 | { | ||
464 | // The file was last modified more than 60 seconds before the crash reporter was launched. Assume it's stale. | ||
465 | llwarns << "File " << mFilename << " is too old!" << llendl; | ||
466 | return; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | } | ||
471 | |||
472 | S32 buf_size = stat_data.st_size; | ||
473 | FILE *fp = fopen(mFilename.c_str(), "rb"); | ||
474 | U8 *buf = new U8[buf_size + 1]; | ||
475 | size_t nread = fread(buf, 1, buf_size, fp); | ||
476 | fclose(fp); | ||
477 | buf[nread] = 0; | ||
478 | |||
479 | mBuf = (char *)buf; | ||
480 | |||
481 | if(isCrashLog) | ||
482 | { | ||
483 | // Crash logs consist of a number of entries, one per crash. | ||
484 | // Each entry is preceeded by "**********" on a line by itself. | ||
485 | // We want only the most recent (i.e. last) one. | ||
486 | const char *sep = "**********"; | ||
487 | const char *start = mBuf.c_str(); | ||
488 | const char *cur = start; | ||
489 | const char *temp = strstr(cur, sep); | ||
490 | |||
491 | while(temp != NULL) | ||
492 | { | ||
493 | // Skip past the marker we just found | ||
494 | cur = temp + strlen(sep); | ||
495 | |||
496 | // and try to find another | ||
497 | temp = strstr(cur, sep); | ||
498 | } | ||
499 | |||
500 | // If there's more than one entry in the log file, strip all but the last one. | ||
501 | if(cur != start) | ||
502 | { | ||
503 | mBuf.erase(0, cur - start); | ||
504 | } | ||
505 | } | ||
506 | |||
507 | mIsValid = TRUE; | ||
508 | delete[] buf; | ||
509 | } | ||
510 | |||
511 | LLString LLFileEncoder::encodeURL(const S32 max_length) | ||
512 | { | ||
513 | LLString result = mFormname; | ||
514 | result.append("="); | ||
515 | |||
516 | S32 i = 0; | ||
517 | |||
518 | if (max_length) | ||
519 | { | ||
520 | if ((S32)mBuf.size() > max_length) | ||
521 | { | ||
522 | i = mBuf.size() - max_length; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | #if 0 | ||
527 | // Plain text version for debugging | ||
528 | result.append(mBuf); | ||
529 | #else | ||
530 | // Not using LLString because of bad performance issues | ||
531 | S32 buf_size = mBuf.size(); | ||
532 | S32 url_buf_size = 3*mBuf.size() + 1; | ||
533 | char *url_buf = new char[url_buf_size]; | ||
534 | |||
535 | S32 cur_pos = 0; | ||
536 | for (; i < buf_size; i++) | ||
537 | { | ||
538 | sprintf(url_buf + cur_pos, "%%%02x", mBuf[i]); | ||
539 | cur_pos += 3; | ||
540 | } | ||
541 | url_buf[i*3] = 0; | ||
542 | |||
543 | result.append(url_buf); | ||
544 | delete[] url_buf; | ||
545 | #endif | ||
546 | return result; | ||
547 | } | ||
548 | |||
549 | LLString encode_string(const char *formname, const LLString &str) | ||
550 | { | ||
551 | LLString result = formname; | ||
552 | result.append("="); | ||
553 | // Not using LLString because of bad performance issues | ||
554 | S32 buf_size = str.size(); | ||
555 | S32 url_buf_size = 3*str.size() + 1; | ||
556 | char *url_buf = new char[url_buf_size]; | ||
557 | |||
558 | S32 cur_pos = 0; | ||
559 | S32 i; | ||
560 | for (i = 0; i < buf_size; i++) | ||
561 | { | ||
562 | sprintf(url_buf + cur_pos, "%%%02x", str[i]); | ||
563 | cur_pos += 3; | ||
564 | } | ||
565 | url_buf[i*3] = 0; | ||
566 | |||
567 | result.append(url_buf); | ||
568 | delete[] url_buf; | ||
569 | return result; | ||
570 | } | ||
diff --git a/linden/indra/linux_crash_logger/llcrashloggerlinux.cpp b/linden/indra/linux_crash_logger/llcrashloggerlinux.cpp new file mode 100644 index 0000000..26a8f0c --- /dev/null +++ b/linden/indra/linux_crash_logger/llcrashloggerlinux.cpp | |||
@@ -0,0 +1,140 @@ | |||
1 | /** | ||
2 | * @file llcrashloggerlinux.cpp | ||
3 | * @brief Linux crash logger implementation | ||
4 | * | ||
5 | * $LicenseInfo:firstyear=2003&license=viewergpl$ | ||
6 | * | ||
7 | * Copyright (c) 2003-2007, Linden Research, Inc. | ||
8 | * | ||
9 | * Second Life Viewer Source Code | ||
10 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
11 | * to you under the terms of the GNU General Public License, version 2.0 | ||
12 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
13 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
14 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
15 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
16 | * | ||
17 | * There are special exceptions to the terms and conditions of the GPL as | ||
18 | * it is applied to this Source Code. View the full text of the exception | ||
19 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
20 | * online at http://secondlife.com/developers/opensource/flossexception | ||
21 | * | ||
22 | * By copying, modifying or distributing this software, you acknowledge | ||
23 | * that you have read and understood your obligations described above, | ||
24 | * and agree to abide by those obligations. | ||
25 | * | ||
26 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
27 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
28 | * COMPLETENESS OR PERFORMANCE. | ||
29 | * $/LicenseInfo$ | ||
30 | */ | ||
31 | |||
32 | #include "llcrashloggerlinux.h" | ||
33 | |||
34 | #include <iostream> | ||
35 | |||
36 | #include "linden_common.h" | ||
37 | |||
38 | #include "boost/tokenizer.hpp" | ||
39 | |||
40 | #include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME | ||
41 | #include "llerror.h" | ||
42 | #include "llfile.h" | ||
43 | #include "lltimer.h" | ||
44 | #include "llstring.h" | ||
45 | #include "lldir.h" | ||
46 | #include "llsdserialize.h" | ||
47 | |||
48 | #if LL_GTK | ||
49 | # include "gtk/gtk.h" | ||
50 | #endif // LL_GTK | ||
51 | |||
52 | #define MAX_LOADSTRING 100 | ||
53 | |||
54 | // These need to be localized. | ||
55 | static const char dialog_text[] = | ||
56 | "Second Life appears to have crashed or frozen last time it ran.\n" | ||
57 | "This crash reporter collects information about your computer's hardware, operating system, and some Second Life logs, all of which are used for debugging purposes only.\n" | ||
58 | "In the space below, please briefly describe what you were doing or trying to do just prior to the crash. Thank you for your help!\n" | ||
59 | "This report is NOT read by Customer Support. If you have billing or other questions, contact support by visiting http://www.secondlife.com/support\n" | ||
60 | "\n" | ||
61 | "Send crash report?"; | ||
62 | |||
63 | static const char dialog_title[] = | ||
64 | "Second Life Crash Logger"; | ||
65 | |||
66 | #if LL_GTK | ||
67 | static void response_callback (GtkDialog *dialog, | ||
68 | gint arg1, | ||
69 | gpointer user_data) | ||
70 | { | ||
71 | gint *response = (gint*)user_data; | ||
72 | *response = arg1; | ||
73 | gtk_widget_destroy(GTK_WIDGET(dialog)); | ||
74 | gtk_main_quit(); | ||
75 | } | ||
76 | #endif // LL_GTK | ||
77 | |||
78 | static BOOL do_ask_dialog(void) | ||
79 | { | ||
80 | #if LL_GTK | ||
81 | gtk_disable_setlocale(); | ||
82 | if (!gtk_init_check(NULL, NULL)) { | ||
83 | llinfos << "Could not initialize GTK for 'ask to send crash report' dialog; not sending report." << llendl; | ||
84 | return FALSE; | ||
85 | } | ||
86 | |||
87 | GtkWidget *win = NULL; | ||
88 | GtkDialogFlags flags = GTK_DIALOG_MODAL; | ||
89 | GtkMessageType messagetype = GTK_MESSAGE_QUESTION; | ||
90 | GtkButtonsType buttons = GTK_BUTTONS_YES_NO; | ||
91 | gint response = GTK_RESPONSE_NONE; | ||
92 | |||
93 | win = gtk_message_dialog_new(NULL, | ||
94 | flags, messagetype, buttons, | ||
95 | dialog_text); | ||
96 | gtk_window_set_type_hint(GTK_WINDOW(win), | ||
97 | GDK_WINDOW_TYPE_HINT_DIALOG); | ||
98 | gtk_window_set_title(GTK_WINDOW(win), dialog_title); | ||
99 | g_signal_connect (win, | ||
100 | "response", | ||
101 | G_CALLBACK (response_callback), | ||
102 | &response); | ||
103 | gtk_widget_show_all (win); | ||
104 | gtk_main(); | ||
105 | |||
106 | return (GTK_RESPONSE_OK == response || | ||
107 | GTK_RESPONSE_YES == response || | ||
108 | GTK_RESPONSE_APPLY == response); | ||
109 | #else | ||
110 | return FALSE; | ||
111 | #endif // LL_GTK | ||
112 | } | ||
113 | |||
114 | LLCrashLoggerLinux::LLCrashLoggerLinux(void) | ||
115 | { | ||
116 | } | ||
117 | |||
118 | LLCrashLoggerLinux::~LLCrashLoggerLinux(void) | ||
119 | { | ||
120 | } | ||
121 | |||
122 | void LLCrashLoggerLinux::gatherPlatformSpecificFiles() | ||
123 | { | ||
124 | mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log").c_str(); | ||
125 | } | ||
126 | |||
127 | bool LLCrashLoggerLinux::mainLoop() | ||
128 | { | ||
129 | if(!do_ask_dialog()) | ||
130 | { | ||
131 | return true; | ||
132 | } | ||
133 | sendCrashLogs(); | ||
134 | return true; | ||
135 | } | ||
136 | |||
137 | void LLCrashLoggerLinux::updateApplication(LLString message) | ||
138 | { | ||
139 | LLCrashLogger::updateApplication(message); | ||
140 | } | ||
diff --git a/linden/indra/linux_crash_logger/llcrashloggerlinux.h b/linden/indra/linux_crash_logger/llcrashloggerlinux.h new file mode 100644 index 0000000..a84ee00 --- /dev/null +++ b/linden/indra/linux_crash_logger/llcrashloggerlinux.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /** | ||
2 | * @file llcrashloggerlinux.h | ||
3 | * @brief Linux crash logger definition | ||
4 | * | ||
5 | * $LicenseInfo:firstyear=2003&license=viewergpl$ | ||
6 | * | ||
7 | * Copyright (c) 2003-2007, Linden Research, Inc. | ||
8 | * | ||
9 | * Second Life Viewer Source Code | ||
10 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
11 | * to you under the terms of the GNU General Public License, version 2.0 | ||
12 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
13 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
14 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
15 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
16 | * | ||
17 | * There are special exceptions to the terms and conditions of the GPL as | ||
18 | * it is applied to this Source Code. View the full text of the exception | ||
19 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
20 | * online at http://secondlife.com/developers/opensource/flossexception | ||
21 | * | ||
22 | * By copying, modifying or distributing this software, you acknowledge | ||
23 | * that you have read and understood your obligations described above, | ||
24 | * and agree to abide by those obligations. | ||
25 | * | ||
26 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
27 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
28 | * COMPLETENESS OR PERFORMANCE. | ||
29 | * $/LicenseInfo$ | ||
30 | */ | ||
31 | |||
32 | #ifndef LLCRASHLOGGERLINUX_H | ||
33 | #define LLCRASHLOGGERLINUX_H | ||
34 | |||
35 | #include "linden_common.h" | ||
36 | #include "llcrashlogger.h" | ||
37 | #include "llstring.h" | ||
38 | |||
39 | class LLCrashLoggerLinux : public LLCrashLogger | ||
40 | { | ||
41 | public: | ||
42 | LLCrashLoggerLinux(void); | ||
43 | ~LLCrashLoggerLinux(void); | ||
44 | virtual bool mainLoop(); | ||
45 | virtual void updateApplication(LLString message = ""); | ||
46 | virtual void gatherPlatformSpecificFiles(); | ||
47 | }; | ||
48 | |||
49 | #endif | ||