summaryrefslogtreecommitdiff
path: root/indra/mac_crash_logger
diff options
context:
space:
mode:
authorKyle Machulis <qdot@lindenlab.com>2007-11-20 23:42:48 +0000
committerKyle Machulis <qdot@lindenlab.com>2007-11-20 23:42:48 +0000
commit2e7c0d973ed28d732ea19762099ed3c55123780e (patch)
tree36b04301d325e07075880a8a64166c5284d1d61f /indra/mac_crash_logger
parent5356b917545d43df5537128245ee5b786b705b90 (diff)
svn merge -r74104:74124 svn+ssh://svn/svn/linden/branches/crash-logger-cleanup-merge-6
Diffstat (limited to 'indra/mac_crash_logger')
-rw-r--r--indra/mac_crash_logger/llcrashloggermac.cpp310
-rw-r--r--indra/mac_crash_logger/llcrashloggermac.h51
-rw-r--r--indra/mac_crash_logger/mac_crash_logger.cpp668
3 files changed, 368 insertions, 661 deletions
diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp
new file mode 100644
index 0000000000..ba50af9d00
--- /dev/null
+++ b/indra/mac_crash_logger/llcrashloggermac.cpp
@@ -0,0 +1,310 @@
+/**
+ * @file llcrashloggermac.cpp
+ * @brief Mac OSX crash logger implementation
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ *
+ * Copyright (c) 2003-2007, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llcrashloggermac.h"
+
+#include <Carbon/Carbon.h>
+#include <iostream>
+#include <sstream>
+
+#include "boost/tokenizer.hpp"
+
+#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
+#include "llerror.h"
+#include "llfile.h"
+#include "lltimer.h"
+#include "llstring.h"
+#include "lldir.h"
+#include "llsdserialize.h"
+
+#define MAX_LOADSTRING 100
+const char* const SETTINGS_FILE_HEADER = "version";
+const S32 SETTINGS_FILE_VERSION = 101;
+
+// Windows Message Handlers
+
+BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog?
+FILE *gDebugFile = NULL;
+
+WindowRef gWindow = NULL;
+EventHandlerRef gEventHandler = NULL;
+LLString gUserNotes = "";
+bool gSendReport = false;
+bool gRememberChoice = false;
+IBNibRef nib = NULL;
+
+OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata)
+{
+ OSStatus result = eventNotHandledErr;
+ OSStatus err;
+ UInt32 evtClass = GetEventClass(event);
+ UInt32 evtKind = GetEventKind(event);
+ if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess))
+ {
+ HICommand cmd;
+ err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd);
+
+
+
+ if(err == noErr)
+ {
+ //Get the value of the checkbox
+ ControlID id;
+ ControlRef checkBox = NULL;
+ id.signature = 'remb';
+ id.id = 0;
+ err = GetControlByID(gWindow, &id, &checkBox);
+
+ if(err == noErr)
+ {
+ if(GetControl32BitValue(checkBox) == kControlCheckBoxCheckedValue)
+ {
+ gRememberChoice = true;
+ }
+ else
+ {
+ gRememberChoice = false;
+ }
+ }
+ switch(cmd.commandID)
+ {
+ case kHICommandOK:
+ {
+ char buffer[65535]; /* Flawfinder: ignore */
+ Size size = sizeof(buffer) - 1;
+ ControlRef textField = NULL;
+
+ id.signature = 'text';
+ id.id = 0;
+
+ err = GetControlByID(gWindow, &id, &textField);
+ if(err == noErr)
+ {
+ // Get the user response text
+ err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size);
+ }
+ if(err == noErr)
+ {
+ // Make sure the string is terminated.
+ buffer[size] = 0;
+ //setUserText(buffer);
+ llinfos << buffer << llendl;
+ }
+
+ // Send the report.
+
+ QuitAppModalLoopForWindow(gWindow);
+ gSendReport = true;
+ result = noErr;
+ }
+ break;
+
+ case kHICommandCancel:
+ QuitAppModalLoopForWindow(gWindow);
+ result = noErr;
+ break;
+ }
+ }
+ }
+
+ return(result);
+}
+
+
+LLCrashLoggerMac::LLCrashLoggerMac(void)
+{
+}
+
+LLCrashLoggerMac::~LLCrashLoggerMac(void)
+{
+}
+
+bool LLCrashLoggerMac::init(void)
+{
+ bool ok = LLCrashLogger::init();
+ if(!ok) return false;
+ // Real UI...
+ OSStatus err;
+
+ err = CreateNibReference(CFSTR("CrashReporter"), &nib);
+
+ if(err == noErr)
+ {
+ err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow);
+ }
+
+ if(err == noErr)
+ {
+ // Set focus to the edit text area
+ ControlRef textField = NULL;
+ ControlID id;
+
+ id.signature = 'text';
+ id.id = 0;
+
+ // Don't set err if any of this fails, since it's non-critical.
+ if(GetControlByID(gWindow, &id, &textField) == noErr)
+ {
+ SetKeyboardFocus(gWindow, textField, kControlFocusNextPart);
+ }
+ }
+
+ if(err == noErr)
+ {
+ ShowWindow(gWindow);
+ }
+
+ if(err == noErr)
+ {
+ // Set up an event handler for the window.
+ EventTypeSpec handlerEvents[] =
+ {
+ { kEventClassCommand, kEventCommandProcess }
+ };
+
+ InstallWindowEventHandler(
+ gWindow,
+ NewEventHandlerUPP(dialogHandler),
+ GetEventTypeCount (handlerEvents),
+ handlerEvents,
+ 0,
+ &gEventHandler);
+ }
+ return true;
+}
+
+void LLCrashLoggerMac::gatherPlatformSpecificFiles()
+{
+ updateApplication("Gathering hardware information...");
+ char path[MAX_PATH];
+ FSRef folder;
+
+ if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr)
+ {
+ // folder is an FSRef to ~/Library/Logs/
+ if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr)
+ {
+ struct stat dw_stat;
+ LLString mBuf;
+ // Try the 10.3 path first...
+ LLString dw_file_name = LLString(path) + LLString("/CrashReporter/Second Life.crash.log");
+ int res = stat(dw_file_name.c_str(), &dw_stat);
+
+ if (res)
+ {
+ // Try the 10.2 one next...
+ dw_file_name = LLString(path) + LLString("/Second Life.crash.log");
+ res = stat(dw_file_name.c_str(), &dw_stat);
+ }
+
+ if (!res)
+ {
+ std::ifstream fp(dw_file_name.c_str());
+ std::stringstream str;
+ if(!fp.is_open()) return;
+ str << fp.rdbuf();
+ mBuf = str.str();
+
+ // Crash logs consist of a number of entries, one per crash.
+ // Each entry is preceeded by "**********" on a line by itself.
+ // We want only the most recent (i.e. last) one.
+ const char *sep = "**********";
+ const char *start = mBuf.c_str();
+ const char *cur = start;
+ const char *temp = strstr(cur, sep);
+
+ while(temp != NULL)
+ {
+ // Skip past the marker we just found
+ cur = temp + strlen(sep); /* Flawfinder: ignore */
+
+ // and try to find another
+ temp = strstr(cur, sep);
+ }
+
+ // If there's more than one entry in the log file, strip all but the last one.
+ if(cur != start)
+ {
+ mBuf.erase(0, cur - start);
+ }
+ mDebugLog["CrashInfo"] = mBuf;
+ }
+ else
+ {
+ llwarns << "Couldn't find any CrashReporter files..." << llendl;
+ }
+ }
+ }
+}
+
+bool LLCrashLoggerMac::mainLoop()
+{
+ OSStatus err = noErr;
+
+ if(err == noErr)
+ {
+ RunAppModalLoopForWindow(gWindow);
+ }
+
+ if(gRememberChoice)
+ {
+ if(gSendReport) saveCrashBehaviorSetting(CRASH_BEHAVIOR_ALWAYS_SEND);
+ else saveCrashBehaviorSetting(CRASH_BEHAVIOR_NEVER_SEND);
+ }
+
+ if(gSendReport)
+ {
+ sendCrashLogs();
+ }
+
+ if(gWindow != NULL)
+ {
+ DisposeWindow(gWindow);
+ }
+
+ if(nib != NULL)
+ {
+ DisposeNibReference(nib);
+ }
+
+ return true;
+}
+
+void LLCrashLoggerMac::updateApplication(LLString message)
+{
+ LLCrashLogger::updateApplication();
+}
+
+bool LLCrashLoggerMac::cleanup()
+{
+ return true;
+}
diff --git a/indra/mac_crash_logger/llcrashloggermac.h b/indra/mac_crash_logger/llcrashloggermac.h
new file mode 100644
index 0000000000..cf4e766bda
--- /dev/null
+++ b/indra/mac_crash_logger/llcrashloggermac.h
@@ -0,0 +1,51 @@
+/**
+ * @file llcrashloggermac.h
+ * @brief Mac OSX crash logger definition
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ *
+ * Copyright (c) 2003-2007, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLCRASHLOGGERMAC_H
+#define LLCRASHLOGGERMAC_H
+
+#include "linden_common.h"
+#include "llcrashlogger.h"
+#include "llstring.h"
+
+class LLCrashLoggerMac : public LLCrashLogger
+{
+public:
+ LLCrashLoggerMac(void);
+ ~LLCrashLoggerMac(void);
+ virtual bool init();
+ virtual bool mainLoop();
+ virtual void updateApplication(LLString message = "");
+ virtual bool cleanup();
+ virtual void gatherPlatformSpecificFiles();
+};
+
+#endif
diff --git a/indra/mac_crash_logger/mac_crash_logger.cpp b/indra/mac_crash_logger/mac_crash_logger.cpp
index 2501b4a521..bf3151a490 100644
--- a/indra/mac_crash_logger/mac_crash_logger.cpp
+++ b/indra/mac_crash_logger/mac_crash_logger.cpp
@@ -31,675 +31,21 @@
#include "linden_common.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <curl/curl.h>
-
-#include "llerror.h"
-#include "lltimer.h"
-#include "lldir.h"
-
-#include "llstring.h"
-
-class LLFileEncoder
-{
-public:
- LLFileEncoder(const char *formname, const char *filename, bool isCrashLog = false);
-
- BOOL isValid() const { return mIsValid; }
- LLString encodeURL(const S32 max_length = 0);
-public:
- BOOL mIsValid;
- LLString mFilename;
- LLString mFormname;
- LLString mBuf;
-};
-
-LLString encode_string(const char *formname, const LLString &str);
-
-#include <Carbon/Carbon.h>
-
-LLString gServerResponse;
-BOOL gSendReport = FALSE;
-LLString gUserserver;
-LLString gUserText;
-WindowRef gWindow = NULL;
-EventHandlerRef gEventHandler = NULL;
-BOOL gCrashInPreviousExec = FALSE;
-time_t gLaunchTime;
-
-size_t curl_download_callback(void *data, size_t size, size_t nmemb,
- void *user_data)
-{
- S32 bytes = size * nmemb;
- char *cdata = (char *) data;
- for (int i =0; i < bytes; i += 1)
- {
- gServerResponse += (cdata[i]);
- }
- return bytes;
-}
-
-OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata)
-{
- OSStatus result = eventNotHandledErr;
- OSStatus err;
- UInt32 evtClass = GetEventClass(event);
- UInt32 evtKind = GetEventKind(event);
-
- if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess))
- {
- HICommand cmd;
- err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd);
-
- if(err == noErr)
- {
- switch(cmd.commandID)
- {
- case kHICommandOK:
- {
- char buffer[65535]; /* Flawfinder: ignore */
- Size size = sizeof(buffer) - 1;
- ControlRef textField = NULL;
- ControlID id;
-
- id.signature = 'text';
- id.id = 0;
-
- err = GetControlByID(gWindow, &id, &textField);
- if(err == noErr)
- {
- // Get the user response text
- err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size);
- }
- if(err == noErr)
- {
- // Make sure the string is terminated.
- buffer[size] = 0;
- gUserText = buffer;
- llinfos << buffer << llendl;
- }
-
- // Send the report.
- gSendReport = TRUE;
-
- QuitAppModalLoopForWindow(gWindow);
- result = noErr;
- }
- break;
-
- case kHICommandCancel:
- QuitAppModalLoopForWindow(gWindow);
- result = noErr;
- break;
- }
- }
- }
-
- return(result);
-}
+#include "llcrashloggermac.h"
int main(int argc, char **argv)
{
- const S32 DW_MAX_SIZE = 100000; // Maximum size to transmit of the Dr. Watson log file
- const S32 SL_MAX_SIZE = 100000; // Maximum size of the Second Life log file.
- int i;
-
- time(&gLaunchTime);
+ //time(&gLaunchTime);
llinfos << "Starting Second Life Viewer Crash Reporter" << llendl;
-
- for(i=1; i<argc; i++)
- {
- if(!strcmp(argv[i], "-previous"))
- {
- gCrashInPreviousExec = TRUE;
- }
- if(!strcmp(argv[i], "-user"))
- {
- if ((i + 1) < argc)
- {
- i++;
- gUserserver = argv[i];
- llinfos << "Got userserver " << gUserserver << llendl;
- }
- }
- }
-
- if( gCrashInPreviousExec )
- {
- llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl;
- }
-
- if(!gCrashInPreviousExec)
- {
- // Delay five seconds to let CrashReporter do its thing.
- sleep(5);
- }
-
-#if 1
- // Real UI...
- OSStatus err;
- IBNibRef nib = NULL;
-
- err = CreateNibReference(CFSTR("CrashReporter"), &nib);
-
- if(err == noErr)
- {
- if(gCrashInPreviousExec)
- {
- err = CreateWindowFromNib(nib, CFSTR("CrashReporterDelayed"), &gWindow);
- }
- else
- {
- err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow);
- }
- }
-
- if(err == noErr)
- {
- // Set focus to the edit text area
- ControlRef textField = NULL;
- ControlID id;
-
- id.signature = 'text';
- id.id = 0;
-
- // Don't set err if any of this fails, since it's non-critical.
- if(GetControlByID(gWindow, &id, &textField) == noErr)
- {
- SetKeyboardFocus(gWindow, textField, kControlFocusNextPart);
- }
- }
-
- if(err == noErr)
- {
- ShowWindow(gWindow);
- }
-
- if(err == noErr)
- {
- // Set up an event handler for the window.
- EventTypeSpec handlerEvents[] =
- {
- { kEventClassCommand, kEventCommandProcess }
- };
-
- InstallWindowEventHandler(
- gWindow,
- NewEventHandlerUPP(dialogHandler),
- GetEventTypeCount (handlerEvents),
- handlerEvents,
- 0,
- &gEventHandler);
- }
-
- if(err == noErr)
- {
- RunAppModalLoopForWindow(gWindow);
- }
-
- if(gWindow != NULL)
- {
- DisposeWindow(gWindow);
- }
-
- if(nib != NULL)
- {
- DisposeNibReference(nib);
- }
-#else
- // Cheap version -- just use the standard system alert.
- SInt16 itemHit = 0;
- AlertStdCFStringAlertParamRec params;
- OSStatus err = noErr;
- DialogRef alert = NULL;
-
- params.version = kStdCFStringAlertVersionOne;
- params.movable = false;
- params.helpButton = false;
- params.defaultText = CFSTR("Send Report");
- params.cancelText = CFSTR("Don't Send Report");
- params.otherText = 0;
- params.defaultButton = kAlertStdAlertOKButton;
- params.cancelButton = kAlertStdAlertCancelButton;
- params.position = kWindowDefaultPosition;
- params.flags = 0;
-
- err = CreateStandardAlert(
- kAlertCautionAlert,
- CFSTR("Second Life appears to have crashed."),
- CFSTR(
- "To help us debug the problem, you can send a crash report to Linden Lab. "
- "The report contains information about your microprocessor type, graphics card, "
- "memory, things that happened during the last run of the program, and the Crash Log "
- "of where the crash occurred.\r"
- "\r"
- "You may also report crashes in the forums, or by sending e-mail to peter@lindenlab.com"),
- &params,
- &alert);
-
- if(err == noErr)
- {
- err = RunStandardAlert(
- alert,
- NULL,
- &itemHit);
- }
-
- if(itemHit == kAlertStdAlertOKButton)
- gSendReport = TRUE;
-#endif
-
- if(!gSendReport)
- {
- // Only send the report if the user agreed to it.
- llinfos << "User cancelled, not sending report" << llendl;
-
- return(0);
- }
-
- // We assume that all the logs we're looking for reside on the current drive
- gDirUtilp->initAppDirs("SecondLife");
-
- int res;
-
- // Lots of silly variable, replicated for each log file.
- LLString db_file_name;
- LLString sl_file_name;
- LLString dw_file_name; // DW file name is a hack for now...
- LLString st_file_name; // stats.log file
- LLString si_file_name; // settings.ini file
-
- LLFileEncoder *db_filep = NULL;
- LLFileEncoder *sl_filep = NULL;
- LLFileEncoder *st_filep = NULL;
- LLFileEncoder *dw_filep = NULL;
- LLFileEncoder *si_filep = NULL;
-
- ///////////////////////////////////
- //
- // We do the parsing for the debug_info file first, as that will
- // give us the location of the SecondLife.log file.
- //
-
- // Figure out the filename of the debug log
- db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log").c_str();
- db_filep = new LLFileEncoder("DB", db_file_name.c_str());
-
- // Get the filename of the SecondLife.log file
-
- // *NOTE: changing the size of either of these buffers will
- // require changing the sscanf() format string to correctly
- // account for it.
- char tmp_sl_name[LL_MAX_PATH]; /* Flawfinder: ignore */
- tmp_sl_name[0] = '\0';
- char tmp_space[MAX_STRING]; /* Flawfinder: ignore */
- tmp_space[0] = '\0';
-
- // Look for it in the debug_info.log file
- if (db_filep->isValid())
- {
- // This was originally scanning for "SL Log: %[^\r\n]", which happily skipped to the next line
- // on debug logs (which don't have anything after "SL Log:" and tried to open a nonsensical filename.
- sscanf(
- db_filep->mBuf.c_str(),
- "SL Log:%254[ ]%1023[^\r\n]",
- tmp_space,
- tmp_sl_name);
- }
- else
- {
- delete db_filep;
- db_filep = NULL;
- }
-
- // If we actually have a legitimate file name, use it.
- if (tmp_sl_name[0])
- {
- sl_file_name = tmp_sl_name;
- llinfos << "Using log file from debug log " << sl_file_name << llendl;
- }
- else
- {
- // Figure out the filename of the second life log
- sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log").c_str();
- }
-
- // Now we get the SecondLife.log file if it's there, and recent enough...
- sl_filep = new LLFileEncoder("SL", sl_file_name.c_str());
- if (!sl_filep->isValid())
- {
- delete sl_filep;
- sl_filep = NULL;
- }
-
- st_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log").c_str();
- st_filep = new LLFileEncoder("ST", st_file_name.c_str());
- if (!st_filep->isValid())
- {
- delete st_filep;
- st_filep = NULL;
- }
-
- si_file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.ini").c_str();
- si_filep = new LLFileEncoder("SI", si_file_name.c_str());
- if (!si_filep->isValid())
- {
- delete si_filep;
- si_filep = NULL;
- }
-
- // MBW -- This needs to go find "~/Library/Logs/CrashReporter/Second Life.crash.log" on 10.3
- // or "~/Library/Logs/Second Life.crash.log" on 10.2.
- {
- char path[MAX_PATH]; /* Flawfinder: ignore */
- FSRef folder;
-
- if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr)
- {
- // folder is an FSRef to ~/Library/Logs/
- if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr)
- {
- struct stat dw_stat;
-// printf("path is %s\n", path);
-
- // Try the 10.3 path first...
- dw_file_name = LLString(path) + LLString("/CrashReporter/Second Life.crash.log");
- res = stat(dw_file_name.c_str(), &dw_stat);
-
- if (res)
- {
- // Try the 10.2 one next...
- dw_file_name = LLString(path) + LLString("/Second Life.crash.log");
- res = stat(dw_file_name.c_str(), &dw_stat);
- }
-
- if (!res)
- {
- dw_filep = new LLFileEncoder("DW", dw_file_name.c_str(), true);
- if (!dw_filep->isValid())
- {
- delete dw_filep;
- dw_filep = NULL;
- }
- }
- else
- {
- llwarns << "Couldn't find any CrashReporter files..." << llendl;
- }
- }
- }
- }
-
- LLString post_data;
- LLString tmp_url_buf;
-
- // Append the userserver
- tmp_url_buf = encode_string("USER", gUserserver);
- post_data += tmp_url_buf;
- llinfos << "PostData:" << post_data << llendl;
-
- if (gCrashInPreviousExec)
- {
- post_data.append("&");
- tmp_url_buf = encode_string("EF", "Y");
- post_data += tmp_url_buf;
- }
-
- if (db_filep)
- {
- post_data.append("&");
- tmp_url_buf = db_filep->encodeURL();
- post_data += tmp_url_buf;
- llinfos << "Sending DB log file" << llendl;
- }
- else
- {
- llinfos << "Not sending DB log file" << llendl;
- }
-
- if (sl_filep)
- {
- post_data.append("&");
- tmp_url_buf = sl_filep->encodeURL(SL_MAX_SIZE);
- post_data += tmp_url_buf;
- llinfos << "Sending SL log file" << llendl;
- }
- else
- {
- llinfos << "Not sending SL log file" << llendl;
- }
-
- if (st_filep)
- {
- post_data.append("&");
- tmp_url_buf = st_filep->encodeURL(SL_MAX_SIZE);
- post_data += tmp_url_buf;
- llinfos << "Sending stats log file" << llendl;
- }
- else
- {
- llinfos << "Not sending stats log file" << llendl;
- }
- if (dw_filep)
+ LLCrashLoggerMac app;
+ app.parseCommandOptions(argc, argv);
+ if(!app.init())
{
- post_data.append("&");
- tmp_url_buf = dw_filep->encodeURL(DW_MAX_SIZE);
- post_data += tmp_url_buf;
+ return 0;
}
- else
- {
- llinfos << "Not sending crash log file" << llendl;
- }
-
- if (si_filep)
- {
- post_data.append("&");
- tmp_url_buf = si_filep->encodeURL();
- post_data += tmp_url_buf;
- llinfos << "Sending settings log file" << llendl;
- }
- else
- {
- llinfos << "Not sending settings.ini file" << llendl;
- }
-
- if (gUserText.size())
- {
- post_data.append("&");
- tmp_url_buf = encode_string("UN", gUserText);
- post_data += tmp_url_buf;
- }
-
- delete db_filep;
- db_filep = NULL;
- delete sl_filep;
- sl_filep = NULL;
- delete dw_filep;
- dw_filep = NULL;
-
- // Debugging spam
-#if 0
- printf("Crash report post data:\n--------\n");
- printf("%s", post_data.getString());
- printf("\n--------\n");
-#endif
-
- // Send the report. Yes, it's this easy.
- {
- CURL *curl = curl_easy_init();
-
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback);
- curl_easy_setopt(curl, CURLOPT_POST, 1);
- curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data.c_str());
- curl_easy_setopt(curl, CURLOPT_URL, "http://secondlife.com/cgi-bin/viewer_crash_reporter2");
-
- llinfos << "Connecting to crash report server" << llendl;
- CURLcode result = curl_easy_perform(curl);
-
- curl_easy_cleanup(curl);
+ app.mainLoop();
- if(result != CURLE_OK)
- {
- llinfos << "Couldn't talk to crash report server" << llendl;
- }
- else
- {
- llinfos << "Response from crash report server:" << llendl;
- llinfos << gServerResponse << llendl;
- }
- }
-
return 0;
}
-
-LLFileEncoder::LLFileEncoder(const char *form_name, const char *filename, bool isCrashLog)
-{
- mFormname = form_name;
- mFilename = filename;
- mIsValid = FALSE;
-
- int res;
-
- struct stat stat_data;
- res = stat(mFilename.c_str(), &stat_data);
- if (res)
- {
- llwarns << "File " << mFilename << " is missing!" << llendl;
- return;
- }
- else
- {
- // Debugging spam
-// llinfos << "File " << mFilename << " is present..." << llendl;
-
- if(!gCrashInPreviousExec && isCrashLog)
- {
- // Make sure the file isn't too old.
- double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec);
-
-// llinfos << "age is " << age << llendl;
-
- if(age > 60.0)
- {
- // The file was last modified more than 60 seconds before the crash reporter was launched. Assume it's stale.
- llwarns << "File " << mFilename << " is too old!" << llendl;
- return;
- }
- }
-
- }
-
- S32 buf_size = stat_data.st_size;
- FILE* fp = fopen(mFilename.c_str(), "rb"); /* Flawfinder: ignore */
- U8 *buf = new U8[buf_size + 1];
- fread(buf, 1, buf_size, fp);
- fclose(fp);
- buf[buf_size] = 0;
-
- mBuf = (char *)buf;
-
- if(isCrashLog)
- {
- // Crash logs consist of a number of entries, one per crash.
- // Each entry is preceeded by "**********" on a line by itself.
- // We want only the most recent (i.e. last) one.
- const char *sep = "**********";
- const char *start = mBuf.c_str();
- const char *cur = start;
- const char *temp = strstr(cur, sep);
-
- while(temp != NULL)
- {
- // Skip past the marker we just found
- cur = temp + strlen(sep); /* Flawfinder: ignore */
-
- // and try to find another
- temp = strstr(cur, sep);
- }
-
- // If there's more than one entry in the log file, strip all but the last one.
- if(cur != start)
- {
- mBuf.erase(0, cur - start);
- }
- }
-
- mIsValid = TRUE;
- delete[] buf;
-}
-
-LLString LLFileEncoder::encodeURL(const S32 max_length)
-{
- LLString result = mFormname;
- result.append("=");
-
- S32 i = 0;
-
- if (max_length)
- {
- if (mBuf.size() > max_length)
- {
- i = mBuf.size() - max_length;
- }
- }
-
-#if 0
- // Plain text version for debugging
- result.append(mBuf);
-#else
- // Not using LLString because of bad performance issues
- S32 buf_size = mBuf.size();
- S32 url_buf_size = 3*mBuf.size() + 1;
- char *url_buf = new char[url_buf_size];
- if (url_buf == NULL)
- {
- llerrs << "Memory Allocation Failed" << llendl;
- return result;
- }
- S32 cur_pos = 0;
- for (; i < buf_size; i++)
- {
- sprintf(url_buf + cur_pos, "%%%02x", mBuf[i]); /* Flawfinder: ignore */
- cur_pos += 3;
- }
- url_buf[i*3] = 0;
-
- result.append(url_buf);
- delete[] url_buf;
-#endif
- return result;
-}
-
-LLString encode_string(const char *formname, const LLString &str)
-{
- LLString result = formname;
- result.append("=");
- // Not using LLString because of bad performance issues
- S32 buf_size = str.size();
- S32 url_buf_size = 3*str.size() + 1;
- char *url_buf = new char[url_buf_size];
- if (url_buf == NULL)
- {
- llerrs << "Memory Allocation Failed" << llendl;
- return result;
- }
-
- S32 cur_pos = 0;
- S32 i;
- for (i = 0; i < buf_size; i++)
- {
- sprintf(url_buf + cur_pos, "%%%02x", str[i]); /* Flawfinder: ignore */
- cur_pos += 3;
- }
- url_buf[i*3] = 0;
-
- result.append(url_buf);
- delete[] url_buf;
- return result;
-}