/ src / client / mac / crash_generation / ConfigFile.mm
ConfigFile.mm
  1  // Copyright 2011 Google LLC
  2  //
  3  // Redistribution and use in source and binary forms, with or without
  4  // modification, are permitted provided that the following conditions are
  5  // met:
  6  //
  7  //     * Redistributions of source code must retain the above copyright
  8  // notice, this list of conditions and the following disclaimer.
  9  //     * Redistributions in binary form must reproduce the above
 10  // copyright notice, this list of conditions and the following disclaimer
 11  // in the documentation and/or other materials provided with the
 12  // distribution.
 13  //     * Neither the name of Google LLC nor the names of its
 14  // contributors may be used to endorse or promote products derived from
 15  // this software without specific prior written permission.
 16  //
 17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 21  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 22  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 23  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 24  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 25  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 27  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28  //
 29  // Utility class that can persist a SimpleStringDictionary to disk.
 30  
 31  #import "client/mac/crash_generation/ConfigFile.h"
 32  
 33  #import <Foundation/Foundation.h>
 34  #include <stdio.h>
 35  #include <sys/time.h>
 36  
 37  #import "client/apple/Framework/BreakpadDefines.h"
 38  #import "common/mac/GTMDefines.h"
 39  
 40  
 41  namespace google_breakpad {
 42  
 43  //=============================================================================
 44  BOOL EnsureDirectoryPathExists(NSString* dirPath) {
 45    NSFileManager* mgr = [NSFileManager defaultManager];
 46  
 47    NSDictionary* attrs =
 48      [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:0750]
 49                                  forKey:NSFilePosixPermissions];
 50  
 51    return [mgr createDirectoryAtPath:dirPath
 52          withIntermediateDirectories:YES
 53                           attributes:attrs
 54                                error:nil];
 55  }
 56  
 57  //=============================================================================
 58  BOOL ConfigFile::WriteData(const void* data, size_t length) {
 59    size_t result = write(config_file_, data, length);
 60  
 61    return result == length;
 62  }
 63  
 64  //=============================================================================
 65  BOOL ConfigFile::AppendConfigData(const char* key,
 66                                    const void* data, size_t length) {
 67    assert(config_file_ != -1);
 68  
 69    if (!key) {
 70      return NO;
 71    }
 72  
 73    if (!data) {
 74      return NO;
 75    }
 76  
 77    // Write the key, \n, length of data (ascii integer), \n, data
 78    char buffer[16];
 79    char nl = '\n';
 80    BOOL result = WriteData(key, strlen(key));
 81  
 82    snprintf(buffer, sizeof(buffer) - 1, "\n%lu\n", length);
 83    result &= WriteData(buffer, strlen(buffer));
 84    result &= WriteData(data, length);
 85    result &= WriteData(&nl, 1);
 86    return result;
 87  }
 88  
 89  //=============================================================================
 90  BOOL ConfigFile::AppendConfigString(const char* key,
 91                                      const char* value) {
 92    return AppendConfigData(key, value, strlen(value));
 93  }
 94  
 95  //=============================================================================
 96  BOOL ConfigFile::AppendCrashTimeParameters(const char* processStartTimeString) {
 97    // Set process uptime parameter
 98    struct timeval tv;
 99    gettimeofday(&tv, NULL);
100  
101    char processUptimeString[32], processCrashtimeString[32];
102    // Set up time if we've received the start time.
103    if (processStartTimeString) {
104      time_t processStartTime = strtol(processStartTimeString, NULL, 10);
105      time_t processUptime = tv.tv_sec - processStartTime;
106      // Store the uptime in milliseconds.
107      snprintf(processUptimeString, sizeof(processUptimeString), "%llu",
108               static_cast<unsigned long long int>(processUptime) * 1000);
109      if (!AppendConfigString(BREAKPAD_PROCESS_UP_TIME, processUptimeString))
110        return false;
111    }
112  
113    snprintf(processCrashtimeString, sizeof(processCrashtimeString), "%llu",
114             static_cast<unsigned long long int>(tv.tv_sec));
115    return AppendConfigString(BREAKPAD_PROCESS_CRASH_TIME,
116                              processCrashtimeString);
117  }
118  
119  //=============================================================================
120  void ConfigFile::WriteFile(const char* directory,
121                             const SimpleStringDictionary* configurationParameters,
122                             const char* dump_dir,
123                             const char* minidump_id) {
124  
125    assert(config_file_ == -1);
126  
127    // Open and write out configuration file preamble
128    if (directory) {
129      snprintf(config_file_path_, sizeof(config_file_path_), "%s/Config-XXXXXX",
130               directory);
131    } else {
132      strlcpy(config_file_path_, "/tmp/Config-XXXXXX",
133              sizeof(config_file_path_));
134    }
135    config_file_ = mkstemp(config_file_path_);
136  
137    if (config_file_ == -1) {
138      return;
139    }
140  
141    has_created_file_ = true;
142  
143    // Add the minidump dir
144    AppendConfigString(kReporterMinidumpDirectoryKey, dump_dir);
145    AppendConfigString(kReporterMinidumpIDKey, minidump_id);
146  
147    // Write out the configuration parameters
148    BOOL result = YES;
149    const SimpleStringDictionary& dictionary = *configurationParameters;
150  
151    const SimpleStringDictionary::Entry* entry = NULL;
152    SimpleStringDictionary::Iterator iter(dictionary);
153  
154    while ((entry = iter.Next())) {
155      result = AppendConfigString(entry->key, entry->value);
156  
157      if (!result)
158        break;
159    }
160    AppendCrashTimeParameters(
161        configurationParameters->GetValueForKey(BREAKPAD_PROCESS_START_TIME));
162  
163    close(config_file_);
164    config_file_ = -1;
165  }
166  
167  } // namespace google_breakpad