diff options
author | Jacek Antonelli | 2008-08-15 23:45:19 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:45:19 -0500 |
commit | b235c59d60472f818a9142c0886b95a0ff4191d7 (patch) | |
tree | d323c55587584b19cc43a03f58a178823f12d3cd /linden/indra/mac_crash_logger/llcrashloggermac.cpp | |
parent | Second Life viewer sources 1.18.5.3 (diff) | |
download | meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.zip meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.tar.gz meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.tar.bz2 meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.tar.xz |
Second Life viewer sources 1.18.6.0-RC
Diffstat (limited to 'linden/indra/mac_crash_logger/llcrashloggermac.cpp')
-rw-r--r-- | linden/indra/mac_crash_logger/llcrashloggermac.cpp | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/linden/indra/mac_crash_logger/llcrashloggermac.cpp b/linden/indra/mac_crash_logger/llcrashloggermac.cpp new file mode 100644 index 0000000..3d8abe5 --- /dev/null +++ b/linden/indra/mac_crash_logger/llcrashloggermac.cpp | |||
@@ -0,0 +1,342 @@ | |||
1 | /** | ||
2 | * @file llcrashloggermac.cpp | ||
3 | * @brief Mac OSX 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 | |||
33 | #include "llcrashloggermac.h" | ||
34 | |||
35 | #include <Carbon/Carbon.h> | ||
36 | #include <iostream> | ||
37 | #include <sstream> | ||
38 | |||
39 | #include "boost/tokenizer.hpp" | ||
40 | |||
41 | #include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME | ||
42 | #include "llerror.h" | ||
43 | #include "llfile.h" | ||
44 | #include "lltimer.h" | ||
45 | #include "llstring.h" | ||
46 | #include "lldir.h" | ||
47 | #include "llsdserialize.h" | ||
48 | |||
49 | #define MAX_LOADSTRING 100 | ||
50 | const char* const SETTINGS_FILE_HEADER = "version"; | ||
51 | const S32 SETTINGS_FILE_VERSION = 101; | ||
52 | |||
53 | // Windows Message Handlers | ||
54 | |||
55 | BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? | ||
56 | FILE *gDebugFile = NULL; | ||
57 | |||
58 | WindowRef gWindow = NULL; | ||
59 | EventHandlerRef gEventHandler = NULL; | ||
60 | LLString gUserNotes = ""; | ||
61 | bool gSendReport = false; | ||
62 | bool gRememberChoice = false; | ||
63 | IBNibRef nib = NULL; | ||
64 | |||
65 | OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata) | ||
66 | { | ||
67 | OSStatus result = eventNotHandledErr; | ||
68 | OSStatus err; | ||
69 | UInt32 evtClass = GetEventClass(event); | ||
70 | UInt32 evtKind = GetEventKind(event); | ||
71 | if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) | ||
72 | { | ||
73 | HICommand cmd; | ||
74 | err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd); | ||
75 | |||
76 | |||
77 | |||
78 | if(err == noErr) | ||
79 | { | ||
80 | //Get the value of the checkbox | ||
81 | ControlID id; | ||
82 | ControlRef checkBox = NULL; | ||
83 | id.signature = 'remb'; | ||
84 | id.id = 0; | ||
85 | err = GetControlByID(gWindow, &id, &checkBox); | ||
86 | |||
87 | if(err == noErr) | ||
88 | { | ||
89 | if(GetControl32BitValue(checkBox) == kControlCheckBoxCheckedValue) | ||
90 | { | ||
91 | gRememberChoice = true; | ||
92 | } | ||
93 | else | ||
94 | { | ||
95 | gRememberChoice = false; | ||
96 | } | ||
97 | } | ||
98 | switch(cmd.commandID) | ||
99 | { | ||
100 | case kHICommandOK: | ||
101 | { | ||
102 | char buffer[65535]; /* Flawfinder: ignore */ | ||
103 | Size size = sizeof(buffer) - 1; | ||
104 | ControlRef textField = NULL; | ||
105 | |||
106 | id.signature = 'text'; | ||
107 | id.id = 0; | ||
108 | |||
109 | err = GetControlByID(gWindow, &id, &textField); | ||
110 | if(err == noErr) | ||
111 | { | ||
112 | // Get the user response text | ||
113 | err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size); | ||
114 | } | ||
115 | if(err == noErr) | ||
116 | { | ||
117 | // Make sure the string is terminated. | ||
118 | buffer[size] = 0; | ||
119 | gUserNotes = buffer; | ||
120 | |||
121 | llinfos << buffer << llendl; | ||
122 | } | ||
123 | |||
124 | // Send the report. | ||
125 | |||
126 | QuitAppModalLoopForWindow(gWindow); | ||
127 | gSendReport = true; | ||
128 | result = noErr; | ||
129 | } | ||
130 | break; | ||
131 | |||
132 | case kHICommandCancel: | ||
133 | QuitAppModalLoopForWindow(gWindow); | ||
134 | result = noErr; | ||
135 | break; | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | |||
140 | return(result); | ||
141 | } | ||
142 | |||
143 | |||
144 | LLCrashLoggerMac::LLCrashLoggerMac(void) | ||
145 | { | ||
146 | } | ||
147 | |||
148 | LLCrashLoggerMac::~LLCrashLoggerMac(void) | ||
149 | { | ||
150 | } | ||
151 | |||
152 | bool LLCrashLoggerMac::init(void) | ||
153 | { | ||
154 | bool ok = LLCrashLogger::init(); | ||
155 | if(!ok) return false; | ||
156 | if(mCrashBehavior != CRASH_BEHAVIOR_ASK) return true; | ||
157 | |||
158 | // Real UI... | ||
159 | OSStatus err; | ||
160 | |||
161 | err = CreateNibReference(CFSTR("CrashReporter"), &nib); | ||
162 | |||
163 | if(err == noErr) | ||
164 | { | ||
165 | err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow); | ||
166 | } | ||
167 | |||
168 | if(err == noErr) | ||
169 | { | ||
170 | // Set focus to the edit text area | ||
171 | ControlRef textField = NULL; | ||
172 | ControlID id; | ||
173 | |||
174 | id.signature = 'text'; | ||
175 | id.id = 0; | ||
176 | |||
177 | // Don't set err if any of this fails, since it's non-critical. | ||
178 | if(GetControlByID(gWindow, &id, &textField) == noErr) | ||
179 | { | ||
180 | SetKeyboardFocus(gWindow, textField, kControlFocusNextPart); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | if(err == noErr) | ||
185 | { | ||
186 | ShowWindow(gWindow); | ||
187 | } | ||
188 | |||
189 | if(err == noErr) | ||
190 | { | ||
191 | // Set up an event handler for the window. | ||
192 | EventTypeSpec handlerEvents[] = | ||
193 | { | ||
194 | { kEventClassCommand, kEventCommandProcess } | ||
195 | }; | ||
196 | |||
197 | InstallWindowEventHandler( | ||
198 | gWindow, | ||
199 | NewEventHandlerUPP(dialogHandler), | ||
200 | GetEventTypeCount (handlerEvents), | ||
201 | handlerEvents, | ||
202 | 0, | ||
203 | &gEventHandler); | ||
204 | } | ||
205 | return true; | ||
206 | } | ||
207 | |||
208 | void LLCrashLoggerMac::gatherPlatformSpecificFiles() | ||
209 | { | ||
210 | updateApplication("Gathering hardware information..."); | ||
211 | char path[MAX_PATH]; | ||
212 | FSRef folder; | ||
213 | |||
214 | if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr) | ||
215 | { | ||
216 | // folder is an FSRef to ~/Library/Logs/ | ||
217 | if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr) | ||
218 | { | ||
219 | struct stat dw_stat; | ||
220 | LLString mBuf; | ||
221 | bool isLeopard = false; | ||
222 | // Try the 10.3 path first... | ||
223 | LLString dw_file_name = LLString(path) + LLString("/CrashReporter/Second Life.crash.log"); | ||
224 | int res = stat(dw_file_name.c_str(), &dw_stat); | ||
225 | |||
226 | if (res) | ||
227 | { | ||
228 | // Try the 10.2 one next... | ||
229 | dw_file_name = LLString(path) + LLString("/Second Life.crash.log"); | ||
230 | res = stat(dw_file_name.c_str(), &dw_stat); | ||
231 | } | ||
232 | |||
233 | if(res) | ||
234 | { | ||
235 | //10.5: Like 10.3+, except it puts the crash time in the file instead of dividing it up | ||
236 | //using asterisks. Get a directory listing, search for files starting with second life, | ||
237 | //use the last one found. | ||
238 | LLString old_file_name, current_file_name, pathname, mask; | ||
239 | pathname = LLString(path) + LLString("/CrashReporter/"); | ||
240 | mask = "Second Life*"; | ||
241 | while(gDirUtilp->getNextFileInDir(pathname, mask, current_file_name, false)) | ||
242 | { | ||
243 | old_file_name = current_file_name; | ||
244 | } | ||
245 | if(old_file_name != "") | ||
246 | { | ||
247 | dw_file_name = pathname + old_file_name; | ||
248 | res=stat(dw_file_name.c_str(), &dw_stat); | ||
249 | isLeopard = true; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | if (!res) | ||
254 | { | ||
255 | std::ifstream fp(dw_file_name.c_str()); | ||
256 | std::stringstream str; | ||
257 | if(!fp.is_open()) return; | ||
258 | str << fp.rdbuf(); | ||
259 | mBuf = str.str(); | ||
260 | |||
261 | if(!isLeopard) | ||
262 | { | ||
263 | // Crash logs consist of a number of entries, one per crash. | ||
264 | // Each entry is preceeded by "**********" on a line by itself. | ||
265 | // We want only the most recent (i.e. last) one. | ||
266 | const char *sep = "**********"; | ||
267 | const char *start = mBuf.c_str(); | ||
268 | const char *cur = start; | ||
269 | const char *temp = strstr(cur, sep); | ||
270 | |||
271 | while(temp != NULL) | ||
272 | { | ||
273 | // Skip past the marker we just found | ||
274 | cur = temp + strlen(sep); /* Flawfinder: ignore */ | ||
275 | |||
276 | // and try to find another | ||
277 | temp = strstr(cur, sep); | ||
278 | } | ||
279 | |||
280 | // If there's more than one entry in the log file, strip all but the last one. | ||
281 | if(cur != start) | ||
282 | { | ||
283 | mBuf.erase(0, cur - start); | ||
284 | } | ||
285 | } | ||
286 | mCrashInfo["CrashLog"] = mBuf; | ||
287 | } | ||
288 | else | ||
289 | { | ||
290 | llwarns << "Couldn't find any CrashReporter files..." << llendl; | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
296 | bool LLCrashLoggerMac::mainLoop() | ||
297 | { | ||
298 | OSStatus err = noErr; | ||
299 | |||
300 | if(err == noErr && mCrashBehavior == CRASH_BEHAVIOR_ASK) | ||
301 | { | ||
302 | RunAppModalLoopForWindow(gWindow); | ||
303 | } | ||
304 | else if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) | ||
305 | { | ||
306 | gSendReport = true; | ||
307 | } | ||
308 | |||
309 | if(gRememberChoice) | ||
310 | { | ||
311 | if(gSendReport) saveCrashBehaviorSetting(CRASH_BEHAVIOR_ALWAYS_SEND); | ||
312 | else saveCrashBehaviorSetting(CRASH_BEHAVIOR_NEVER_SEND); | ||
313 | } | ||
314 | |||
315 | if(gSendReport) | ||
316 | { | ||
317 | setUserText(gUserNotes); | ||
318 | sendCrashLogs(); | ||
319 | } | ||
320 | |||
321 | if(gWindow != NULL) | ||
322 | { | ||
323 | DisposeWindow(gWindow); | ||
324 | } | ||
325 | |||
326 | if(nib != NULL) | ||
327 | { | ||
328 | DisposeNibReference(nib); | ||
329 | } | ||
330 | |||
331 | return true; | ||
332 | } | ||
333 | |||
334 | void LLCrashLoggerMac::updateApplication(LLString message) | ||
335 | { | ||
336 | LLCrashLogger::updateApplication(); | ||
337 | } | ||
338 | |||
339 | bool LLCrashLoggerMac::cleanup() | ||
340 | { | ||
341 | return true; | ||
342 | } | ||