diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/mac_crash_logger | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/mac_crash_logger')
-rw-r--r-- | linden/indra/mac_crash_logger/mac_crash_logger.cpp | 688 |
1 files changed, 688 insertions, 0 deletions
diff --git a/linden/indra/mac_crash_logger/mac_crash_logger.cpp b/linden/indra/mac_crash_logger/mac_crash_logger.cpp new file mode 100644 index 0000000..177a4b5 --- /dev/null +++ b/linden/indra/mac_crash_logger/mac_crash_logger.cpp | |||
@@ -0,0 +1,688 @@ | |||
1 | /** | ||
2 | * @file mac_crash_logger.cpp | ||
3 | * @brief Mac OSX crash logger implementation | ||
4 | * | ||
5 | * Copyright (c) 2003-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | #include <stdio.h> | ||
31 | #include <stdlib.h> | ||
32 | //#include <direct.h> | ||
33 | #include <time.h> | ||
34 | #include <sys/types.h> | ||
35 | #include <sys/stat.h> | ||
36 | #include <unistd.h> | ||
37 | |||
38 | #include <curl/curl.h> | ||
39 | |||
40 | #include "llerror.h" | ||
41 | #include "lltimer.h" | ||
42 | #include "lldir.h" | ||
43 | |||
44 | #include "llstring.h" | ||
45 | |||
46 | class LLFileEncoder | ||
47 | { | ||
48 | public: | ||
49 | LLFileEncoder(const char *formname, const char *filename, bool isCrashLog = false); | ||
50 | |||
51 | BOOL isValid() const { return mIsValid; } | ||
52 | LLString encodeURL(const S32 max_length = 0); | ||
53 | public: | ||
54 | BOOL mIsValid; | ||
55 | LLString mFilename; | ||
56 | LLString mFormname; | ||
57 | LLString mBuf; | ||
58 | }; | ||
59 | |||
60 | LLString encode_string(const char *formname, const LLString &str); | ||
61 | |||
62 | #include <Carbon/Carbon.h> | ||
63 | |||
64 | LLString gServerResponse; | ||
65 | BOOL gSendReport = FALSE; | ||
66 | LLString gUserserver; | ||
67 | LLString gUserText; | ||
68 | WindowRef gWindow = NULL; | ||
69 | EventHandlerRef gEventHandler = NULL; | ||
70 | BOOL gCrashInPreviousExec = FALSE; | ||
71 | time_t gLaunchTime; | ||
72 | |||
73 | size_t curl_download_callback(void *data, size_t size, size_t nmemb, | ||
74 | void *user_data) | ||
75 | { | ||
76 | S32 bytes = size * nmemb; | ||
77 | char *cdata = (char *) data; | ||
78 | for (int i =0; i < bytes; i += 1) | ||
79 | { | ||
80 | gServerResponse += (cdata[i]); | ||
81 | } | ||
82 | return bytes; | ||
83 | } | ||
84 | |||
85 | OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata) | ||
86 | { | ||
87 | OSStatus result = eventNotHandledErr; | ||
88 | OSStatus err; | ||
89 | UInt32 evtClass = GetEventClass(event); | ||
90 | UInt32 evtKind = GetEventKind(event); | ||
91 | |||
92 | if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) | ||
93 | { | ||
94 | HICommand cmd; | ||
95 | err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd); | ||
96 | |||
97 | if(err == noErr) | ||
98 | { | ||
99 | switch(cmd.commandID) | ||
100 | { | ||
101 | case kHICommandOK: | ||
102 | { | ||
103 | char buffer[65535]; | ||
104 | Size size = sizeof(buffer) - 1; | ||
105 | ControlRef textField = NULL; | ||
106 | ControlID id; | ||
107 | |||
108 | id.signature = 'text'; | ||
109 | id.id = 0; | ||
110 | |||
111 | err = GetControlByID(gWindow, &id, &textField); | ||
112 | if(err == noErr) | ||
113 | { | ||
114 | // Get the user response text | ||
115 | err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size); | ||
116 | } | ||
117 | if(err == noErr) | ||
118 | { | ||
119 | // Make sure the string is terminated. | ||
120 | buffer[size] = 0; | ||
121 | gUserText = buffer; | ||
122 | llinfos << buffer << llendl; | ||
123 | } | ||
124 | |||
125 | // Send the report. | ||
126 | gSendReport = TRUE; | ||
127 | |||
128 | QuitAppModalLoopForWindow(gWindow); | ||
129 | result = noErr; | ||
130 | } | ||
131 | break; | ||
132 | |||
133 | case kHICommandCancel: | ||
134 | QuitAppModalLoopForWindow(gWindow); | ||
135 | result = noErr; | ||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | |||
141 | return(result); | ||
142 | } | ||
143 | |||
144 | int main(int argc, char **argv) | ||
145 | { | ||
146 | const S32 DW_MAX_SIZE = 100000; // Maximum size to transmit of the Dr. Watson log file | ||
147 | const S32 SL_MAX_SIZE = 100000; // Maximum size of the Second Life log file. | ||
148 | int i; | ||
149 | |||
150 | time(&gLaunchTime); | ||
151 | |||
152 | llinfos << "Starting Second Life Viewer Crash Reporter" << llendl; | ||
153 | |||
154 | for(i=1; i<argc; i++) | ||
155 | { | ||
156 | if(!strcmp(argv[i], "-previous")) | ||
157 | { | ||
158 | gCrashInPreviousExec = TRUE; | ||
159 | } | ||
160 | if(!strcmp(argv[i], "-user")) | ||
161 | { | ||
162 | if ((i + 1) < argc) | ||
163 | { | ||
164 | i++; | ||
165 | gUserserver = argv[i]; | ||
166 | llinfos << "Got userserver " << gUserserver << llendl; | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | if( gCrashInPreviousExec ) | ||
172 | { | ||
173 | llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl; | ||
174 | } | ||
175 | |||
176 | if(!gCrashInPreviousExec) | ||
177 | { | ||
178 | // Delay five seconds to let CrashReporter do its thing. | ||
179 | sleep(5); | ||
180 | } | ||
181 | |||
182 | #if 1 | ||
183 | // Real UI... | ||
184 | OSStatus err; | ||
185 | IBNibRef nib = NULL; | ||
186 | |||
187 | err = CreateNibReference(CFSTR("CrashReporter"), &nib); | ||
188 | |||
189 | if(err == noErr) | ||
190 | { | ||
191 | if(gCrashInPreviousExec) | ||
192 | { | ||
193 | err = CreateWindowFromNib(nib, CFSTR("CrashReporterDelayed"), &gWindow); | ||
194 | } | ||
195 | else | ||
196 | { | ||
197 | err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | if(err == noErr) | ||
202 | { | ||
203 | // Set focus to the edit text area | ||
204 | ControlRef textField = NULL; | ||
205 | ControlID id; | ||
206 | |||
207 | id.signature = 'text'; | ||
208 | id.id = 0; | ||
209 | |||
210 | // Don't set err if any of this fails, since it's non-critical. | ||
211 | if(GetControlByID(gWindow, &id, &textField) == noErr) | ||
212 | { | ||
213 | SetKeyboardFocus(gWindow, textField, kControlFocusNextPart); | ||
214 | } | ||
215 | } | ||
216 | |||
217 | if(err == noErr) | ||
218 | { | ||
219 | ShowWindow(gWindow); | ||
220 | } | ||
221 | |||
222 | if(err == noErr) | ||
223 | { | ||
224 | // Set up an event handler for the window. | ||
225 | EventTypeSpec handlerEvents[] = | ||
226 | { | ||
227 | { kEventClassCommand, kEventCommandProcess } | ||
228 | }; | ||
229 | |||
230 | InstallWindowEventHandler( | ||
231 | gWindow, | ||
232 | NewEventHandlerUPP(dialogHandler), | ||
233 | GetEventTypeCount (handlerEvents), | ||
234 | handlerEvents, | ||
235 | 0, | ||
236 | &gEventHandler); | ||
237 | } | ||
238 | |||
239 | if(err == noErr) | ||
240 | { | ||
241 | RunAppModalLoopForWindow(gWindow); | ||
242 | } | ||
243 | |||
244 | if(gWindow != NULL) | ||
245 | { | ||
246 | DisposeWindow(gWindow); | ||
247 | } | ||
248 | |||
249 | if(nib != NULL) | ||
250 | { | ||
251 | DisposeNibReference(nib); | ||
252 | } | ||
253 | #else | ||
254 | // Cheap version -- just use the standard system alert. | ||
255 | SInt16 itemHit = 0; | ||
256 | AlertStdCFStringAlertParamRec params; | ||
257 | OSStatus err = noErr; | ||
258 | DialogRef alert = NULL; | ||
259 | |||
260 | params.version = kStdCFStringAlertVersionOne; | ||
261 | params.movable = false; | ||
262 | params.helpButton = false; | ||
263 | params.defaultText = CFSTR("Send Report"); | ||
264 | params.cancelText = CFSTR("Don't Send Report"); | ||
265 | params.otherText = 0; | ||
266 | params.defaultButton = kAlertStdAlertOKButton; | ||
267 | params.cancelButton = kAlertStdAlertCancelButton; | ||
268 | params.position = kWindowDefaultPosition; | ||
269 | params.flags = 0; | ||
270 | |||
271 | err = CreateStandardAlert( | ||
272 | kAlertCautionAlert, | ||
273 | CFSTR("Second Life appears to have crashed."), | ||
274 | CFSTR( | ||
275 | "To help us debug the problem, you can send a crash report to Linden Lab. " | ||
276 | "The report contains information about your microprocessor type, graphics card, " | ||
277 | "memory, things that happened during the last run of the program, and the Crash Log " | ||
278 | "of where the crash occurred.\r" | ||
279 | "\r" | ||
280 | "You may also report crashes in the forums, or by sending e-mail to peter@lindenlab.com"), | ||
281 | ¶ms, | ||
282 | &alert); | ||
283 | |||
284 | if(err == noErr) | ||
285 | { | ||
286 | err = RunStandardAlert( | ||
287 | alert, | ||
288 | NULL, | ||
289 | &itemHit); | ||
290 | } | ||
291 | |||
292 | if(itemHit == kAlertStdAlertOKButton) | ||
293 | gSendReport = TRUE; | ||
294 | #endif | ||
295 | |||
296 | if(!gSendReport) | ||
297 | { | ||
298 | // Only send the report if the user agreed to it. | ||
299 | llinfos << "User cancelled, not sending report" << llendl; | ||
300 | |||
301 | return(0); | ||
302 | } | ||
303 | |||
304 | // We assume that all the logs we're looking for reside on the current drive | ||
305 | gDirUtilp->initAppDirs("SecondLife"); | ||
306 | |||
307 | int res; | ||
308 | |||
309 | // Lots of silly variable, replicated for each log file. | ||
310 | LLString db_file_name; | ||
311 | LLString sl_file_name; | ||
312 | LLString dw_file_name; // DW file name is a hack for now... | ||
313 | LLString st_file_name; // stats.log file | ||
314 | LLString si_file_name; // settings.ini file | ||
315 | |||
316 | LLFileEncoder *db_filep = NULL; | ||
317 | LLFileEncoder *sl_filep = NULL; | ||
318 | LLFileEncoder *st_filep = NULL; | ||
319 | LLFileEncoder *dw_filep = NULL; | ||
320 | LLFileEncoder *si_filep = NULL; | ||
321 | |||
322 | /////////////////////////////////// | ||
323 | // | ||
324 | // We do the parsing for the debug_info file first, as that will | ||
325 | // give us the location of the SecondLife.log file. | ||
326 | // | ||
327 | |||
328 | // Figure out the filename of the debug log | ||
329 | db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log").c_str(); | ||
330 | db_filep = new LLFileEncoder("DB", db_file_name.c_str()); | ||
331 | |||
332 | // Get the filename of the SecondLife.log file | ||
333 | char tmp_sl_name[MAX_PATH]; | ||
334 | tmp_sl_name[0] = '\0'; | ||
335 | char tmp_space[256]; | ||
336 | tmp_space[0] = '\0'; | ||
337 | |||
338 | // Look for it in the debug_info.log file | ||
339 | if (db_filep->isValid()) | ||
340 | { | ||
341 | // This was originally scanning for "SL Log: %[^\r\n]", which happily skipped to the next line | ||
342 | // on debug logs (which don't have anything after "SL Log:" and tried to open a nonsensical filename. | ||
343 | sscanf(db_filep->mBuf.c_str(), "SL Log:%[ ]%[^\r\n]", tmp_space, tmp_sl_name); | ||
344 | } | ||
345 | else | ||
346 | { | ||
347 | delete db_filep; | ||
348 | db_filep = NULL; | ||
349 | } | ||
350 | |||
351 | // If we actually have a legitimate file name, use it. | ||
352 | if (tmp_sl_name[0]) | ||
353 | { | ||
354 | sl_file_name = tmp_sl_name; | ||
355 | llinfos << "Using log file from debug log " << sl_file_name << llendl; | ||
356 | } | ||
357 | else | ||
358 | { | ||
359 | // Figure out the filename of the second life log | ||
360 | sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log").c_str(); | ||
361 | } | ||
362 | |||
363 | // Now we get the SecondLife.log file if it's there, and recent enough... | ||
364 | sl_filep = new LLFileEncoder("SL", sl_file_name.c_str()); | ||
365 | if (!sl_filep->isValid()) | ||
366 | { | ||
367 | delete sl_filep; | ||
368 | sl_filep = NULL; | ||
369 | } | ||
370 | |||
371 | st_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log").c_str(); | ||
372 | st_filep = new LLFileEncoder("ST", st_file_name.c_str()); | ||
373 | if (!st_filep->isValid()) | ||
374 | { | ||
375 | delete st_filep; | ||
376 | st_filep = NULL; | ||
377 | } | ||
378 | |||
379 | si_file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.ini").c_str(); | ||
380 | si_filep = new LLFileEncoder("SI", si_file_name.c_str()); | ||
381 | if (!si_filep->isValid()) | ||
382 | { | ||
383 | delete si_filep; | ||
384 | si_filep = NULL; | ||
385 | } | ||
386 | |||
387 | // MBW -- This needs to go find "~/Library/Logs/CrashReporter/Second Life.crash.log" on 10.3 | ||
388 | // or "~/Library/Logs/Second Life.crash.log" on 10.2. | ||
389 | { | ||
390 | char path[MAX_PATH]; | ||
391 | FSRef folder; | ||
392 | |||
393 | if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr) | ||
394 | { | ||
395 | // folder is an FSRef to ~/Library/Logs/ | ||
396 | if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr) | ||
397 | { | ||
398 | struct stat dw_stat; | ||
399 | // printf("path is %s\n", path); | ||
400 | |||
401 | // Try the 10.3 path first... | ||
402 | dw_file_name = LLString(path) + LLString("/CrashReporter/Second Life.crash.log"); | ||
403 | res = stat(dw_file_name.c_str(), &dw_stat); | ||
404 | |||
405 | if (res) | ||
406 | { | ||
407 | // Try the 10.2 one next... | ||
408 | dw_file_name = LLString(path) + LLString("/Second Life.crash.log"); | ||
409 | res = stat(dw_file_name.c_str(), &dw_stat); | ||
410 | } | ||
411 | |||
412 | if (!res) | ||
413 | { | ||
414 | dw_filep = new LLFileEncoder("DW", dw_file_name.c_str(), true); | ||
415 | if (!dw_filep->isValid()) | ||
416 | { | ||
417 | delete dw_filep; | ||
418 | dw_filep = NULL; | ||
419 | } | ||
420 | } | ||
421 | else | ||
422 | { | ||
423 | llwarns << "Couldn't find any CrashReporter files..." << llendl; | ||
424 | } | ||
425 | } | ||
426 | } | ||
427 | } | ||
428 | |||
429 | LLString post_data; | ||
430 | LLString tmp_url_buf; | ||
431 | |||
432 | // Append the userserver | ||
433 | tmp_url_buf = encode_string("USER", gUserserver); | ||
434 | post_data += tmp_url_buf; | ||
435 | llinfos << "PostData:" << post_data << llendl; | ||
436 | |||
437 | if (gCrashInPreviousExec) | ||
438 | { | ||
439 | post_data.append("&"); | ||
440 | tmp_url_buf = encode_string("EF", "Y"); | ||
441 | post_data += tmp_url_buf; | ||
442 | } | ||
443 | |||
444 | if (db_filep) | ||
445 | { | ||
446 | post_data.append("&"); | ||
447 | tmp_url_buf = db_filep->encodeURL(); | ||
448 | post_data += tmp_url_buf; | ||
449 | llinfos << "Sending DB log file" << llendl; | ||
450 | } | ||
451 | else | ||
452 | { | ||
453 | llinfos << "Not sending DB log file" << llendl; | ||
454 | } | ||
455 | |||
456 | if (sl_filep) | ||
457 | { | ||
458 | post_data.append("&"); | ||
459 | tmp_url_buf = sl_filep->encodeURL(SL_MAX_SIZE); | ||
460 | post_data += tmp_url_buf; | ||
461 | llinfos << "Sending SL log file" << llendl; | ||
462 | } | ||
463 | else | ||
464 | { | ||
465 | llinfos << "Not sending SL log file" << llendl; | ||
466 | } | ||
467 | |||
468 | if (st_filep) | ||
469 | { | ||
470 | post_data.append("&"); | ||
471 | tmp_url_buf = st_filep->encodeURL(SL_MAX_SIZE); | ||
472 | post_data += tmp_url_buf; | ||
473 | llinfos << "Sending stats log file" << llendl; | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | llinfos << "Not sending stats log file" << llendl; | ||
478 | } | ||
479 | |||
480 | if (dw_filep) | ||
481 | { | ||
482 | post_data.append("&"); | ||
483 | tmp_url_buf = dw_filep->encodeURL(DW_MAX_SIZE); | ||
484 | post_data += tmp_url_buf; | ||
485 | } | ||
486 | else | ||
487 | { | ||
488 | llinfos << "Not sending crash log file" << llendl; | ||
489 | } | ||
490 | |||
491 | if (si_filep) | ||
492 | { | ||
493 | post_data.append("&"); | ||
494 | tmp_url_buf = si_filep->encodeURL(); | ||
495 | post_data += tmp_url_buf; | ||
496 | llinfos << "Sending settings log file" << llendl; | ||
497 | } | ||
498 | else | ||
499 | { | ||
500 | llinfos << "Not sending settings.ini file" << llendl; | ||
501 | } | ||
502 | |||
503 | if (gUserText.size()) | ||
504 | { | ||
505 | post_data.append("&"); | ||
506 | tmp_url_buf = encode_string("UN", gUserText); | ||
507 | post_data += tmp_url_buf; | ||
508 | } | ||
509 | |||
510 | delete db_filep; | ||
511 | db_filep = NULL; | ||
512 | delete sl_filep; | ||
513 | sl_filep = NULL; | ||
514 | delete dw_filep; | ||
515 | dw_filep = NULL; | ||
516 | |||
517 | // Debugging spam | ||
518 | #if 0 | ||
519 | printf("Crash report post data:\n--------\n"); | ||
520 | printf("%s", post_data.getString()); | ||
521 | printf("\n--------\n"); | ||
522 | #endif | ||
523 | |||
524 | // Send the report. Yes, it's this easy. | ||
525 | { | ||
526 | CURL *curl = curl_easy_init(); | ||
527 | |||
528 | curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); | ||
529 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback); | ||
530 | curl_easy_setopt(curl, CURLOPT_POST, 1); | ||
531 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data.c_str()); | ||
532 | curl_easy_setopt(curl, CURLOPT_URL, "http://secondlife.com/cgi-bin/viewer_crash_reporter2"); | ||
533 | |||
534 | llinfos << "Connecting to crash report server" << llendl; | ||
535 | CURLcode result = curl_easy_perform(curl); | ||
536 | |||
537 | curl_easy_cleanup(curl); | ||
538 | |||
539 | if(result != CURLE_OK) | ||
540 | { | ||
541 | llinfos << "Couldn't talk to crash report server" << llendl; | ||
542 | } | ||
543 | else | ||
544 | { | ||
545 | llinfos << "Response from crash report server:" << llendl; | ||
546 | llinfos << gServerResponse << llendl; | ||
547 | } | ||
548 | } | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | LLFileEncoder::LLFileEncoder(const char *form_name, const char *filename, bool isCrashLog) | ||
554 | { | ||
555 | mFormname = form_name; | ||
556 | mFilename = filename; | ||
557 | mIsValid = FALSE; | ||
558 | |||
559 | int res; | ||
560 | |||
561 | struct stat stat_data; | ||
562 | res = stat(mFilename.c_str(), &stat_data); | ||
563 | if (res) | ||
564 | { | ||
565 | llwarns << "File " << mFilename << " is missing!" << llendl; | ||
566 | return; | ||
567 | } | ||
568 | else | ||
569 | { | ||
570 | // Debugging spam | ||
571 | // llinfos << "File " << mFilename << " is present..." << llendl; | ||
572 | |||
573 | if(!gCrashInPreviousExec && isCrashLog) | ||
574 | { | ||
575 | // Make sure the file isn't too old. | ||
576 | double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec); | ||
577 | |||
578 | // llinfos << "age is " << age << llendl; | ||
579 | |||
580 | if(age > 60.0) | ||
581 | { | ||
582 | // The file was last modified more than 60 seconds before the crash reporter was launched. Assume it's stale. | ||
583 | llwarns << "File " << mFilename << " is too old!" << llendl; | ||
584 | return; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | } | ||
589 | |||
590 | S32 buf_size = stat_data.st_size; | ||
591 | FILE *fp = fopen(mFilename.c_str(), "rb"); | ||
592 | U8 *buf = new U8[buf_size + 1]; | ||
593 | fread(buf, 1, buf_size, fp); | ||
594 | fclose(fp); | ||
595 | buf[buf_size] = 0; | ||
596 | |||
597 | mBuf = (char *)buf; | ||
598 | |||
599 | if(isCrashLog) | ||
600 | { | ||
601 | // Crash logs consist of a number of entries, one per crash. | ||
602 | // Each entry is preceeded by "**********" on a line by itself. | ||
603 | // We want only the most recent (i.e. last) one. | ||
604 | const char *sep = "**********"; | ||
605 | const char *start = mBuf.c_str(); | ||
606 | const char *cur = start; | ||
607 | const char *temp = strstr(cur, sep); | ||
608 | |||
609 | while(temp != NULL) | ||
610 | { | ||
611 | // Skip past the marker we just found | ||
612 | cur = temp + strlen(sep); | ||
613 | |||
614 | // and try to find another | ||
615 | temp = strstr(cur, sep); | ||
616 | } | ||
617 | |||
618 | // If there's more than one entry in the log file, strip all but the last one. | ||
619 | if(cur != start) | ||
620 | { | ||
621 | mBuf.erase(0, cur - start); | ||
622 | } | ||
623 | } | ||
624 | |||
625 | mIsValid = TRUE; | ||
626 | delete[] buf; | ||
627 | } | ||
628 | |||
629 | LLString LLFileEncoder::encodeURL(const S32 max_length) | ||
630 | { | ||
631 | LLString result = mFormname; | ||
632 | result.append("="); | ||
633 | |||
634 | S32 i = 0; | ||
635 | |||
636 | if (max_length) | ||
637 | { | ||
638 | if (mBuf.size() > max_length) | ||
639 | { | ||
640 | i = mBuf.size() - max_length; | ||
641 | } | ||
642 | } | ||
643 | |||
644 | #if 0 | ||
645 | // Plain text version for debugging | ||
646 | result.append(mBuf); | ||
647 | #else | ||
648 | // Not using LLString because of bad performance issues | ||
649 | S32 buf_size = mBuf.size(); | ||
650 | S32 url_buf_size = 3*mBuf.size() + 1; | ||
651 | char *url_buf = new char[url_buf_size]; | ||
652 | |||
653 | S32 cur_pos = 0; | ||
654 | for (; i < buf_size; i++) | ||
655 | { | ||
656 | sprintf(url_buf + cur_pos, "%%%02x", mBuf[i]); | ||
657 | cur_pos += 3; | ||
658 | } | ||
659 | url_buf[i*3] = 0; | ||
660 | |||
661 | result.append(url_buf); | ||
662 | delete[] url_buf; | ||
663 | #endif | ||
664 | return result; | ||
665 | } | ||
666 | |||
667 | LLString encode_string(const char *formname, const LLString &str) | ||
668 | { | ||
669 | LLString result = formname; | ||
670 | result.append("="); | ||
671 | // Not using LLString because of bad performance issues | ||
672 | S32 buf_size = str.size(); | ||
673 | S32 url_buf_size = 3*str.size() + 1; | ||
674 | char *url_buf = new char[url_buf_size]; | ||
675 | |||
676 | S32 cur_pos = 0; | ||
677 | S32 i; | ||
678 | for (i = 0; i < buf_size; i++) | ||
679 | { | ||
680 | sprintf(url_buf + cur_pos, "%%%02x", str[i]); | ||
681 | cur_pos += 3; | ||
682 | } | ||
683 | url_buf[i*3] = 0; | ||
684 | |||
685 | result.append(url_buf); | ||
686 | delete[] url_buf; | ||
687 | return result; | ||
688 | } | ||