Extracting the config file class from the Inspector to be able to reuse it.
This will be needed for iOS implementation, where the Inspector won't be used, but where a config file will still be needed, because the uploads won't happen just after the crash, but on a next run. Review URL: http://breakpad.appspot.com/309001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@852 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
ad8682bbca
commit
da1c36d03e
@ -35,6 +35,9 @@
|
|||||||
/* End PBXAggregateTarget section */
|
/* End PBXAggregateTarget section */
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
163201D61443019E00C4DBF5 /* ConfigFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 163201D41443019E00C4DBF5 /* ConfigFile.h */; };
|
||||||
|
163201D71443019E00C4DBF5 /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 163201D51443019E00C4DBF5 /* ConfigFile.mm */; };
|
||||||
|
163201E31443029300C4DBF5 /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 163201D51443019E00C4DBF5 /* ConfigFile.mm */; };
|
||||||
3329D4ED0FA16D820007BBC5 /* Breakpad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3329D4EC0FA16D820007BBC5 /* Breakpad.xib */; };
|
3329D4ED0FA16D820007BBC5 /* Breakpad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3329D4EC0FA16D820007BBC5 /* Breakpad.xib */; };
|
||||||
33880C800F9E097100817F82 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 33880C7E0F9E097100817F82 /* InfoPlist.strings */; };
|
33880C800F9E097100817F82 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 33880C7E0F9E097100817F82 /* InfoPlist.strings */; };
|
||||||
4084699D0F5D9CF900FDCA37 /* crash_report_sender.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */; };
|
4084699D0F5D9CF900FDCA37 /* crash_report_sender.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */; };
|
||||||
@ -544,6 +547,8 @@
|
|||||||
0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
||||||
1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||||
|
163201D41443019E00C4DBF5 /* ConfigFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConfigFile.h; path = crash_generation/ConfigFile.h; sourceTree = "<group>"; };
|
||||||
|
163201D51443019E00C4DBF5 /* ConfigFile.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = ConfigFile.mm; path = crash_generation/ConfigFile.mm; sourceTree = "<group>"; };
|
||||||
32DBCF5E0370ADEE00C91783 /* Breakpad_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Breakpad_Prefix.pch; path = Framework/Breakpad_Prefix.pch; sourceTree = "<group>"; };
|
32DBCF5E0370ADEE00C91783 /* Breakpad_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Breakpad_Prefix.pch; path = Framework/Breakpad_Prefix.pch; sourceTree = "<group>"; };
|
||||||
3329D4EC0FA16D820007BBC5 /* Breakpad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Breakpad.xib; path = sender/Breakpad.xib; sourceTree = "<group>"; };
|
3329D4EC0FA16D820007BBC5 /* Breakpad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Breakpad.xib; path = sender/Breakpad.xib; sourceTree = "<group>"; };
|
||||||
33880C7F0F9E097100817F82 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = sender/English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
33880C7F0F9E097100817F82 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = sender/English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
@ -958,6 +963,8 @@
|
|||||||
F92C53B50ECCE799009BE4BA /* crash_generation */ = {
|
F92C53B50ECCE799009BE4BA /* crash_generation */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
163201D41443019E00C4DBF5 /* ConfigFile.h */,
|
||||||
|
163201D51443019E00C4DBF5 /* ConfigFile.mm */,
|
||||||
D2F9A4C4121336C7002747C1 /* client_info.h */,
|
D2F9A4C4121336C7002747C1 /* client_info.h */,
|
||||||
D2F9A4C5121336C7002747C1 /* crash_generation_client.h */,
|
D2F9A4C5121336C7002747C1 /* crash_generation_client.h */,
|
||||||
D2F9A4C6121336C7002747C1 /* crash_generation_client.cc */,
|
D2F9A4C6121336C7002747C1 /* crash_generation_client.cc */,
|
||||||
@ -1098,6 +1105,7 @@
|
|||||||
D2F9A4C9121336C7002747C1 /* client_info.h in Headers */,
|
D2F9A4C9121336C7002747C1 /* client_info.h in Headers */,
|
||||||
D2F9A4CA121336C7002747C1 /* crash_generation_client.h in Headers */,
|
D2F9A4CA121336C7002747C1 /* crash_generation_client.h in Headers */,
|
||||||
D2F9A4CC121336C7002747C1 /* crash_generation_server.h in Headers */,
|
D2F9A4CC121336C7002747C1 /* crash_generation_server.h in Headers */,
|
||||||
|
163201D61443019E00C4DBF5 /* ConfigFile.h in Headers */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -1621,6 +1629,7 @@
|
|||||||
F92C56340ECD0DF1009BE4BA /* OnDemandServer.mm in Sources */,
|
F92C56340ECD0DF1009BE4BA /* OnDemandServer.mm in Sources */,
|
||||||
D2F9A4CB121336C7002747C1 /* crash_generation_client.cc in Sources */,
|
D2F9A4CB121336C7002747C1 /* crash_generation_client.cc in Sources */,
|
||||||
D2F9A4CD121336C7002747C1 /* crash_generation_server.cc in Sources */,
|
D2F9A4CD121336C7002747C1 /* crash_generation_server.cc in Sources */,
|
||||||
|
163201D71443019E00C4DBF5 /* ConfigFile.mm in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -1691,6 +1700,7 @@
|
|||||||
files = (
|
files = (
|
||||||
F92C53B80ECCE7B3009BE4BA /* Inspector.mm in Sources */,
|
F92C53B80ECCE7B3009BE4BA /* Inspector.mm in Sources */,
|
||||||
F9286B3A0F7EB25800A4DCC8 /* InspectorMain.mm in Sources */,
|
F9286B3A0F7EB25800A4DCC8 /* InspectorMain.mm in Sources */,
|
||||||
|
163201E31443029300C4DBF5 /* ConfigFile.mm in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
83
src/client/mac/crash_generation/ConfigFile.h
Normal file
83
src/client/mac/crash_generation/ConfigFile.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// Copyright (c) 2011, Google Inc.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
// Utility class that can persist a SimpleStringDictionary to disk.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "common/mac/SimpleStringDictionary.h"
|
||||||
|
|
||||||
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
BOOL EnsureDirectoryPathExists(NSString *dirPath);
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
class ConfigFile {
|
||||||
|
public:
|
||||||
|
ConfigFile() {
|
||||||
|
config_file_ = -1;
|
||||||
|
config_file_path_[0] = 0;
|
||||||
|
has_created_file_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
~ConfigFile() {
|
||||||
|
};
|
||||||
|
|
||||||
|
void WriteFile(const char* directory,
|
||||||
|
const SimpleStringDictionary *configurationParameters,
|
||||||
|
const char *dump_dir,
|
||||||
|
const char *minidump_id);
|
||||||
|
|
||||||
|
const char *GetFilePath() { return config_file_path_; }
|
||||||
|
|
||||||
|
void Unlink() {
|
||||||
|
if (config_file_ != -1)
|
||||||
|
unlink(config_file_path_);
|
||||||
|
|
||||||
|
config_file_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BOOL WriteData(const void *data, size_t length);
|
||||||
|
|
||||||
|
BOOL AppendConfigData(const char *key,
|
||||||
|
const void *data,
|
||||||
|
size_t length);
|
||||||
|
|
||||||
|
BOOL AppendConfigString(const char *key,
|
||||||
|
const char *value);
|
||||||
|
|
||||||
|
BOOL AppendCrashTimeParameters(const char *processStartTimeString);
|
||||||
|
|
||||||
|
int config_file_; // descriptor for config file
|
||||||
|
char config_file_path_[PATH_MAX]; // Path to configuration file
|
||||||
|
bool has_created_file_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace google_breakpad
|
229
src/client/mac/crash_generation/ConfigFile.mm
Normal file
229
src/client/mac/crash_generation/ConfigFile.mm
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
// Copyright (c) 2011, Google Inc.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
// Utility class that can persist a SimpleStringDictionary to disk.
|
||||||
|
|
||||||
|
#import "client/mac/crash_generation/ConfigFile.h"
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#import "client/mac/Framework/Breakpad.h"
|
||||||
|
#import "common/mac/SimpleStringDictionary.h"
|
||||||
|
#import "GTMDefines.h"
|
||||||
|
|
||||||
|
#define VERBOSE 0
|
||||||
|
|
||||||
|
#if VERBOSE
|
||||||
|
bool gDebugLog = true;
|
||||||
|
#else
|
||||||
|
bool gDebugLog = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEBUGLOG if (gDebugLog) fprintf
|
||||||
|
|
||||||
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
BOOL EnsureDirectoryPathExists(NSString *dirPath) {
|
||||||
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
||||||
|
|
||||||
|
// If we got a relative path, prepend the current directory
|
||||||
|
if (![dirPath isAbsolutePath])
|
||||||
|
dirPath =
|
||||||
|
[[mgr currentDirectoryPath] stringByAppendingPathComponent:dirPath];
|
||||||
|
|
||||||
|
NSString *path = dirPath;
|
||||||
|
|
||||||
|
// Ensure that no file exists within the path which would block creation
|
||||||
|
while (1) {
|
||||||
|
BOOL isDir;
|
||||||
|
if ([mgr fileExistsAtPath:path isDirectory:&isDir]) {
|
||||||
|
if (isDir)
|
||||||
|
break;
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = [path stringByDeletingLastPathComponent];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path now contains the first valid directory (or is empty)
|
||||||
|
if (![path length])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
NSString *common =
|
||||||
|
[dirPath commonPrefixWithString:path options:NSLiteralSearch];
|
||||||
|
|
||||||
|
// If everything is good
|
||||||
|
if ([common isEqualToString:dirPath])
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
// Break up the difference into components
|
||||||
|
NSString *diff = [dirPath substringFromIndex:[common length] + 1];
|
||||||
|
NSArray *components = [diff pathComponents];
|
||||||
|
NSUInteger count = [components count];
|
||||||
|
|
||||||
|
// Rebuild the path one component at a time
|
||||||
|
NSDictionary *attrs =
|
||||||
|
[NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:0750]
|
||||||
|
forKey:NSFilePosixPermissions];
|
||||||
|
path = common;
|
||||||
|
for (NSUInteger i = 0; i < count; ++i) {
|
||||||
|
path = [path stringByAppendingPathComponent:[components objectAtIndex:i]];
|
||||||
|
|
||||||
|
if (![mgr createDirectoryAtPath:path attributes:attrs])
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
BOOL ConfigFile::WriteData(const void *data, size_t length) {
|
||||||
|
size_t result = write(config_file_, data, length);
|
||||||
|
|
||||||
|
return result == length;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
BOOL ConfigFile::AppendConfigData(const char *key,
|
||||||
|
const void *data, size_t length) {
|
||||||
|
assert(config_file_ != -1);
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
DEBUGLOG(stderr, "Breakpad: Missing Key\n");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
DEBUGLOG(stderr, "Breakpad: Missing data for key: %s\n", key ? key :
|
||||||
|
"<Unknown Key>");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the key, \n, length of data (ascii integer), \n, data
|
||||||
|
char buffer[16];
|
||||||
|
char nl = '\n';
|
||||||
|
BOOL result = WriteData(key, strlen(key));
|
||||||
|
|
||||||
|
snprintf(buffer, sizeof(buffer) - 1, "\n%lu\n", length);
|
||||||
|
result &= WriteData(buffer, strlen(buffer));
|
||||||
|
result &= WriteData(data, length);
|
||||||
|
result &= WriteData(&nl, 1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
BOOL ConfigFile::AppendConfigString(const char *key,
|
||||||
|
const char *value) {
|
||||||
|
return AppendConfigData(key, value, strlen(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
BOOL ConfigFile::AppendCrashTimeParameters(const char *processStartTimeString) {
|
||||||
|
// Set process uptime parameter
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
char processUptimeString[32], processCrashtimeString[32];
|
||||||
|
// Set up time if we've received the start time.
|
||||||
|
if (processStartTimeString) {
|
||||||
|
time_t processStartTime = strtol(processStartTimeString, NULL, 10);
|
||||||
|
time_t processUptime = tv.tv_sec - processStartTime;
|
||||||
|
sprintf(processUptimeString, "%zd", processUptime);
|
||||||
|
if (!AppendConfigString(BREAKPAD_PROCESS_UP_TIME, processUptimeString))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(processCrashtimeString, "%zd", tv.tv_sec);
|
||||||
|
return AppendConfigString(BREAKPAD_PROCESS_CRASH_TIME,
|
||||||
|
processCrashtimeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
void ConfigFile::WriteFile(const char* directory,
|
||||||
|
const SimpleStringDictionary *configurationParameters,
|
||||||
|
const char *dump_dir,
|
||||||
|
const char *minidump_id) {
|
||||||
|
|
||||||
|
assert(config_file_ == -1);
|
||||||
|
|
||||||
|
// Open and write out configuration file preamble
|
||||||
|
if (directory) {
|
||||||
|
snprintf(config_file_path_, sizeof(config_file_path_), "%s/Config-XXXXXX",
|
||||||
|
directory);
|
||||||
|
} else {
|
||||||
|
strlcpy(config_file_path_, "/tmp/Config-XXXXXX",
|
||||||
|
sizeof(config_file_path_));
|
||||||
|
}
|
||||||
|
config_file_ = mkstemp(config_file_path_);
|
||||||
|
|
||||||
|
if (config_file_ == -1) {
|
||||||
|
DEBUGLOG(stderr,
|
||||||
|
"mkstemp(config_file_path_) == -1 (%s)\n",
|
||||||
|
strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUGLOG(stderr, "Writing config file to (%s)\n", config_file_path_);
|
||||||
|
}
|
||||||
|
|
||||||
|
has_created_file_ = true;
|
||||||
|
|
||||||
|
// Add the minidump dir
|
||||||
|
AppendConfigString(kReporterMinidumpDirectoryKey, dump_dir);
|
||||||
|
AppendConfigString(kReporterMinidumpIDKey, minidump_id);
|
||||||
|
|
||||||
|
// Write out the configuration parameters
|
||||||
|
BOOL result = YES;
|
||||||
|
const SimpleStringDictionary &dictionary = *configurationParameters;
|
||||||
|
|
||||||
|
const KeyValueEntry *entry = NULL;
|
||||||
|
SimpleStringDictionaryIterator iter(dictionary);
|
||||||
|
|
||||||
|
while ((entry = iter.Next())) {
|
||||||
|
DEBUGLOG(stderr,
|
||||||
|
"config: (%s) -> (%s)\n",
|
||||||
|
entry->GetKey(),
|
||||||
|
entry->GetValue());
|
||||||
|
result = AppendConfigString(entry->GetKey(), entry->GetValue());
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
AppendCrashTimeParameters(
|
||||||
|
configurationParameters->GetValueForKey(BREAKPAD_PROCESS_START_TIME));
|
||||||
|
|
||||||
|
close(config_file_);
|
||||||
|
config_file_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace google_breakpad
|
@ -35,10 +35,9 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
|
|
||||||
|
#import "client/mac/crash_generation/ConfigFile.h"
|
||||||
#import "client/mac/handler/minidump_generator.h"
|
#import "client/mac/handler/minidump_generator.h"
|
||||||
|
|
||||||
#define VERBOSE 0
|
|
||||||
|
|
||||||
extern bool gDebugLog;
|
extern bool gDebugLog;
|
||||||
|
|
||||||
#define DEBUGLOG if (gDebugLog) fprintf
|
#define DEBUGLOG if (gDebugLog) fprintf
|
||||||
@ -80,48 +79,6 @@ using google_breakpad::MinidumpGenerator;
|
|||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
BOOL EnsureDirectoryPathExists(NSString *dirPath);
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
class ConfigFile {
|
|
||||||
public:
|
|
||||||
ConfigFile() {
|
|
||||||
config_file_ = -1;
|
|
||||||
config_file_path_[0] = 0;
|
|
||||||
has_created_file_ = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
~ConfigFile() {
|
|
||||||
};
|
|
||||||
|
|
||||||
void WriteFile(const SimpleStringDictionary *configurationParameters,
|
|
||||||
const char *dump_dir,
|
|
||||||
const char *minidump_id);
|
|
||||||
|
|
||||||
const char *GetFilePath() { return config_file_path_; }
|
|
||||||
|
|
||||||
void Unlink() {
|
|
||||||
if (config_file_ != -1)
|
|
||||||
unlink(config_file_path_);
|
|
||||||
|
|
||||||
config_file_ = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BOOL WriteData(const void *data, size_t length);
|
|
||||||
|
|
||||||
BOOL AppendConfigData(const char *key,
|
|
||||||
const void *data,
|
|
||||||
size_t length);
|
|
||||||
|
|
||||||
BOOL AppendConfigString(const char *key,
|
|
||||||
const char *value);
|
|
||||||
|
|
||||||
int config_file_; // descriptor for config file
|
|
||||||
char config_file_path_[PATH_MAX]; // Path to configuration file
|
|
||||||
bool has_created_file_;
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
class MinidumpLocation {
|
class MinidumpLocation {
|
||||||
public:
|
public:
|
||||||
@ -186,8 +143,6 @@ class Inspector {
|
|||||||
kern_return_t SendAcknowledgement();
|
kern_return_t SendAcknowledgement();
|
||||||
void LaunchReporter(const char *inConfigFilePath);
|
void LaunchReporter(const char *inConfigFilePath);
|
||||||
|
|
||||||
void SetCrashTimeParameters();
|
|
||||||
|
|
||||||
// The bootstrap port in which the inspector is registered and into which it
|
// The bootstrap port in which the inspector is registered and into which it
|
||||||
// must check in.
|
// must check in.
|
||||||
mach_port_t bootstrap_subset_port_;
|
mach_port_t bootstrap_subset_port_;
|
||||||
|
@ -35,7 +35,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#import "client/mac/crash_generation/Inspector.h"
|
#import "client/mac/crash_generation/Inspector.h"
|
||||||
|
|
||||||
@ -49,159 +48,8 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#if VERBOSE
|
|
||||||
bool gDebugLog = true;
|
|
||||||
#else
|
|
||||||
bool gDebugLog = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
BOOL EnsureDirectoryPathExists(NSString *dirPath) {
|
|
||||||
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
||||||
|
|
||||||
// If we got a relative path, prepend the current directory
|
|
||||||
if (![dirPath isAbsolutePath])
|
|
||||||
dirPath = [[mgr currentDirectoryPath] stringByAppendingPathComponent:dirPath];
|
|
||||||
|
|
||||||
NSString *path = dirPath;
|
|
||||||
|
|
||||||
// Ensure that no file exists within the path which would block creation
|
|
||||||
while (1) {
|
|
||||||
BOOL isDir;
|
|
||||||
if ([mgr fileExistsAtPath:path isDirectory:&isDir]) {
|
|
||||||
if (isDir)
|
|
||||||
break;
|
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
path = [path stringByDeletingLastPathComponent];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Path now contains the first valid directory (or is empty)
|
|
||||||
if (![path length])
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
NSString *common =
|
|
||||||
[dirPath commonPrefixWithString:path options:NSLiteralSearch];
|
|
||||||
|
|
||||||
// If everything is good
|
|
||||||
if ([common isEqualToString:dirPath])
|
|
||||||
return YES;
|
|
||||||
|
|
||||||
// Break up the difference into components
|
|
||||||
NSString *diff = [dirPath substringFromIndex:[common length] + 1];
|
|
||||||
NSArray *components = [diff pathComponents];
|
|
||||||
NSUInteger count = [components count];
|
|
||||||
|
|
||||||
// Rebuild the path one component at a time
|
|
||||||
NSDictionary *attrs =
|
|
||||||
[NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:0750]
|
|
||||||
forKey:NSFilePosixPermissions];
|
|
||||||
path = common;
|
|
||||||
for (NSUInteger i = 0; i < count; ++i) {
|
|
||||||
path = [path stringByAppendingPathComponent:[components objectAtIndex:i]];
|
|
||||||
|
|
||||||
if (![mgr createDirectoryAtPath:path attributes:attrs])
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
BOOL ConfigFile::WriteData(const void *data, size_t length) {
|
|
||||||
size_t result = write(config_file_, data, length);
|
|
||||||
|
|
||||||
return result == length;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
BOOL ConfigFile::AppendConfigData(const char *key,
|
|
||||||
const void *data, size_t length) {
|
|
||||||
assert(config_file_ != -1);
|
|
||||||
|
|
||||||
if (!key) {
|
|
||||||
DEBUGLOG(stderr, "Breakpad: Missing Key\n");
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
DEBUGLOG(stderr, "Breakpad: Missing data for key: %s\n", key ? key :
|
|
||||||
"<Unknown Key>");
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the key, \n, length of data (ascii integer), \n, data
|
|
||||||
char buffer[16];
|
|
||||||
char nl = '\n';
|
|
||||||
BOOL result = WriteData(key, strlen(key));
|
|
||||||
|
|
||||||
snprintf(buffer, sizeof(buffer) - 1, "\n%lu\n", length);
|
|
||||||
result &= WriteData(buffer, strlen(buffer));
|
|
||||||
result &= WriteData(data, length);
|
|
||||||
result &= WriteData(&nl, 1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
BOOL ConfigFile::AppendConfigString(const char *key,
|
|
||||||
const char *value) {
|
|
||||||
return AppendConfigData(key, value, strlen(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
void ConfigFile::WriteFile(const SimpleStringDictionary *configurationParameters,
|
|
||||||
const char *dump_dir,
|
|
||||||
const char *minidump_id) {
|
|
||||||
|
|
||||||
assert(config_file_ == -1);
|
|
||||||
|
|
||||||
// Open and write out configuration file preamble
|
|
||||||
strlcpy(config_file_path_, "/tmp/Config-XXXXXX",
|
|
||||||
sizeof(config_file_path_));
|
|
||||||
config_file_ = mkstemp(config_file_path_);
|
|
||||||
|
|
||||||
if (config_file_ == -1) {
|
|
||||||
DEBUGLOG(stderr,
|
|
||||||
"mkstemp(config_file_path_) == -1 (%s)\n",
|
|
||||||
strerror(errno));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DEBUGLOG(stderr, "Writing config file to (%s)\n", config_file_path_);
|
|
||||||
}
|
|
||||||
|
|
||||||
has_created_file_ = true;
|
|
||||||
|
|
||||||
// Add the minidump dir
|
|
||||||
AppendConfigString(kReporterMinidumpDirectoryKey, dump_dir);
|
|
||||||
AppendConfigString(kReporterMinidumpIDKey, minidump_id);
|
|
||||||
|
|
||||||
// Write out the configuration parameters
|
|
||||||
BOOL result = YES;
|
|
||||||
const SimpleStringDictionary &dictionary = *configurationParameters;
|
|
||||||
|
|
||||||
const KeyValueEntry *entry = NULL;
|
|
||||||
SimpleStringDictionaryIterator iter(dictionary);
|
|
||||||
|
|
||||||
while ((entry = iter.Next())) {
|
|
||||||
DEBUGLOG(stderr,
|
|
||||||
"config: (%s) -> (%s)\n",
|
|
||||||
entry->GetKey(),
|
|
||||||
entry->GetValue());
|
|
||||||
result = AppendConfigString(entry->GetKey(), entry->GetValue());
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(config_file_);
|
|
||||||
config_file_ = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
void Inspector::Inspect(const char *receive_port_name) {
|
void Inspector::Inspect(const char *receive_port_name) {
|
||||||
kern_return_t result = ResetBootstrapPort();
|
kern_return_t result = ResetBootstrapPort();
|
||||||
@ -414,30 +262,6 @@ kern_return_t Inspector::ReadMessages() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Sets keys in the parameters dictionary that are specific to process uptime.
|
|
||||||
// The two we set are process up time, and process crash time.
|
|
||||||
void Inspector::SetCrashTimeParameters() {
|
|
||||||
// Set process uptime parameter
|
|
||||||
struct timeval tv;
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
|
|
||||||
char processUptimeString[32], processCrashtimeString[32];
|
|
||||||
const char *processStartTimeString =
|
|
||||||
config_params_.GetValueForKey(BREAKPAD_PROCESS_START_TIME);
|
|
||||||
|
|
||||||
// Set up time if we've received the start time.
|
|
||||||
if (processStartTimeString) {
|
|
||||||
time_t processStartTime = strtol(processStartTimeString, NULL, 10);
|
|
||||||
time_t processUptime = tv.tv_sec - processStartTime;
|
|
||||||
sprintf(processUptimeString, "%zd", processUptime);
|
|
||||||
config_params_.SetKeyValue(BREAKPAD_PROCESS_UP_TIME, processUptimeString);
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(processCrashtimeString, "%zd", tv.tv_sec);
|
|
||||||
config_params_.SetKeyValue(BREAKPAD_PROCESS_CRASH_TIME,
|
|
||||||
processCrashtimeString);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Inspector::InspectTask() {
|
bool Inspector::InspectTask() {
|
||||||
// keep the task quiet while we're looking at it
|
// keep the task quiet while we're looking at it
|
||||||
task_suspend(remote_task_);
|
task_suspend(remote_task_);
|
||||||
@ -448,7 +272,6 @@ bool Inspector::InspectTask() {
|
|||||||
const char *minidumpDirectory =
|
const char *minidumpDirectory =
|
||||||
config_params_.GetValueForKey(BREAKPAD_DUMP_DIRECTORY);
|
config_params_.GetValueForKey(BREAKPAD_DUMP_DIRECTORY);
|
||||||
|
|
||||||
SetCrashTimeParameters();
|
|
||||||
// If the client app has not specified a minidump directory,
|
// If the client app has not specified a minidump directory,
|
||||||
// use a default of Library/<kDefaultLibrarySubdirectory>/<Product Name>
|
// use a default of Library/<kDefaultLibrarySubdirectory>/<Product Name>
|
||||||
if (!minidumpDirectory || 0 == strlen(minidumpDirectory)) {
|
if (!minidumpDirectory || 0 == strlen(minidumpDirectory)) {
|
||||||
@ -499,7 +322,8 @@ bool Inspector::InspectTask() {
|
|||||||
[minidumpPath UTF8String]);
|
[minidumpPath UTF8String]);
|
||||||
|
|
||||||
|
|
||||||
config_file_.WriteFile( &config_params_,
|
config_file_.WriteFile( 0,
|
||||||
|
&config_params_,
|
||||||
minidumpLocation.GetPath(),
|
minidumpLocation.GetPath(),
|
||||||
minidumpLocation.GetID());
|
minidumpLocation.GetID());
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ class SimpleStringDictionary {
|
|||||||
// Given |key|, returns its corresponding |value|.
|
// Given |key|, returns its corresponding |value|.
|
||||||
// If |key| is NULL, an assert will fire or NULL will be returned. If |key|
|
// If |key| is NULL, an assert will fire or NULL will be returned. If |key|
|
||||||
// is not found or is an empty string, NULL is returned.
|
// is not found or is an empty string, NULL is returned.
|
||||||
const char *GetValueForKey(const char *key);
|
const char *GetValueForKey(const char *key) const;
|
||||||
|
|
||||||
// Stores a string |value| represented by |key|. If |key| is NULL or an empty
|
// Stores a string |value| represented by |key|. If |key| is NULL or an empty
|
||||||
// string, this will assert (or do nothing). If |value| is NULL then
|
// string, this will assert (or do nothing). If |value| is NULL then
|
||||||
|
@ -55,13 +55,13 @@ int SimpleStringDictionary::GetCount() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
const char *SimpleStringDictionary::GetValueForKey(const char *key) {
|
const char *SimpleStringDictionary::GetValueForKey(const char *key) const {
|
||||||
assert(key);
|
assert(key);
|
||||||
if (!key)
|
if (!key)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
||||||
KeyValueEntry &entry = entries_[i];
|
const KeyValueEntry &entry = entries_[i];
|
||||||
if (entry.IsActive() && !strcmp(entry.GetKey(), key)) {
|
if (entry.IsActive() && !strcmp(entry.GetKey(), key)) {
|
||||||
return entry.GetValue();
|
return entry.GetValue();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user