aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/linux_crash_logger
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/linux_crash_logger/files.lst2
-rw-r--r--linden/indra/linux_crash_logger/linux_crash_logger.cpp538
-rw-r--r--linden/indra/linux_crash_logger/llcrashloggerlinux.cpp140
-rw-r--r--linden/indra/linux_crash_logger/llcrashloggerlinux.h49
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 @@
1llcrashlogger/llcrashlogger.cpp
1linux_crash_logger/linux_crash_logger.cpp 2linux_crash_logger/linux_crash_logger.cpp
3linux_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.
53static 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
62static const char dialog_title[] =
63"Second Life Crash Logger";
64
65
66class LLFileEncoder
67{
68public:
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);
73public:
74 BOOL mIsValid;
75 LLString mFilename;
76 LLString mFormname;
77 LLString mBuf;
78};
79
80LLString encode_string(const char *formname, const LLString &str);
81
82LLString gServerResponse;
83BOOL gSendReport = FALSE;
84LLString gUserserver;
85LLString gUserText;
86BOOL gCrashInPreviousExec = FALSE;
87time_t gLaunchTime;
88
89static 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
102static 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
113static 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
150int main(int argc, char **argv) 34int 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
435LLFileEncoder::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
511LLString 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
549LLString 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.
55static 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
63static const char dialog_title[] =
64"Second Life Crash Logger";
65
66#if LL_GTK
67static 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
78static 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
114LLCrashLoggerLinux::LLCrashLoggerLinux(void)
115{
116}
117
118LLCrashLoggerLinux::~LLCrashLoggerLinux(void)
119{
120}
121
122void LLCrashLoggerLinux::gatherPlatformSpecificFiles()
123{
124 mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log").c_str();
125}
126
127bool LLCrashLoggerLinux::mainLoop()
128{
129 if(!do_ask_dialog())
130 {
131 return true;
132 }
133 sendCrashLogs();
134 return true;
135}
136
137void 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
39class LLCrashLoggerLinux : public LLCrashLogger
40{
41public:
42 LLCrashLoggerLinux(void);
43 ~LLCrashLoggerLinux(void);
44 virtual bool mainLoop();
45 virtual void updateApplication(LLString message = "");
46 virtual void gatherPlatformSpecificFiles();
47};
48
49#endif