summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Joshua Hill2010-06-20 22:02:18 -0400
committerGravatar Joshua Hill2010-06-21 03:59:31 -0400
commit24afafe06f902bfd9f5652beb8797f24033c68bc (patch)
treec998387441a8e044a07cb3a5ae1282543ddaebad /src
parent2a2934ca1568dffe69da9a20420c7c0c71376bce (diff)
downloadidevicerestore-24afafe06f902bfd9f5652beb8797f24033c68bc.tar.gz
idevicerestore-24afafe06f902bfd9f5652beb8797f24033c68bc.tar.bz2
Archived for historical reasons
Diffstat (limited to 'src')
-rw-r--r--src/activate.h13
-rw-r--r--src/asr.c2
-rw-r--r--src/asr.h9
-rw-r--r--src/common.c108
-rw-r--r--src/common.h151
-rw-r--r--src/dfu.c84
-rw-r--r--src/dfu.h24
-rw-r--r--src/idevicerestore.c306
-rw-r--r--src/idevicerestore.h146
-rw-r--r--src/img3.h9
-rw-r--r--src/ipsw.c2
-rw-r--r--src/ipsw.h8
-rw-r--r--src/normal.c48
-rw-r--r--src/normal.h17
-rw-r--r--src/recovery.c47
-rw-r--r--src/recovery.h20
-rw-r--r--src/restore.c219
-rw-r--r--src/restore.h32
-rw-r--r--src/tss.h9
19 files changed, 837 insertions, 417 deletions
diff --git a/src/activate.h b/src/activate.h
index f992d4f..00510d3 100644
--- a/src/activate.h
+++ b/src/activate.h
@@ -19,8 +19,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef ACTIVATE_H
-#define ACTIVATE_H
+#ifndef IDEVICERESTORE_ACTIVATE_H
+#define IDEVICERESTORE_ACTIVATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
#include <plist/plist.h>
#include <libimobiledevice/lockdown.h>
@@ -29,4 +33,9 @@ int activate_device(const char* uuid);
int activate_check_status(const char* uuid);
int activate_fetch_record(lockdownd_client_t lockdown, plist_t* record);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/src/asr.c b/src/asr.c
index c7b6147..2331660 100644
--- a/src/asr.c
+++ b/src/asr.c
@@ -283,7 +283,7 @@ int asr_send_payload(idevice_connection_t asr, const char* filesystem) {
bytes += size;
progress = ((double) bytes/ (double) length) * 100.0;
- print_progress_bar("Extracting", progress);
+ print_progress_bar(progress);
}
diff --git a/src/asr.h b/src/asr.h
index 29210ce..1423496 100644
--- a/src/asr.h
+++ b/src/asr.h
@@ -22,6 +22,10 @@
#ifndef IDEVICERESTORE_ASR_H
#define IDEVICERESTORE_ASR_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <libimobiledevice/libimobiledevice.h>
int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr);
@@ -33,4 +37,9 @@ int asr_perform_validation(idevice_connection_t asr, const char* filesystem);
int asr_send_payload(idevice_connection_t asr, const char* filesystem);
int asr_handle_oob_data_request(idevice_connection_t asr, plist_t packet, FILE* file);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/src/common.c b/src/common.c
new file mode 100644
index 0000000..07a7075
--- /dev/null
+++ b/src/common.c
@@ -0,0 +1,108 @@
+/*
+ * common.c
+ * Misc functions used in idevicerestore
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "common.h"
+
+int idevicerestore_debug = 0;
+
+int write_file(const char* filename, const void* data, size_t size) {
+ size_t bytes = 0;
+ FILE* file = NULL;
+
+ debug("Writing data to %s\n", filename);
+ file = fopen(filename, "wb");
+ if (file == NULL) {
+ error("read_file: Unable to open file %s\n", filename);
+ return -1;
+ }
+
+ bytes = fwrite(data, 1, size, file);
+ fclose(file);
+
+ if (bytes != size) {
+ error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, bytes, size);
+ return -1;
+ }
+
+ return size;
+}
+
+int read_file(const char* filename, void** data, size_t* size) {
+ size_t bytes = 0;
+ size_t length = 0;
+ FILE* file = NULL;
+ char* buffer = NULL;
+ debug("Reading data from %s\n", filename);
+
+ *size = 0;
+ *data = NULL;
+
+ file = fopen(filename, "rb");
+ if (file == NULL) {
+ error("read_file: File %s not found\n", filename);
+ return -1;
+ }
+
+ fseek(file, 0, SEEK_END);
+ length = ftell(file);
+ rewind(file);
+
+ buffer = (char*) malloc(length);
+ if (buffer == NULL) {
+ error("ERROR: Out of memory\n");
+ fclose(file);
+ return -1;
+ }
+ bytes = fread(buffer, 1, length, file);
+ fclose(file);
+
+ if (bytes != length) {
+ error("ERROR: Unable to read entire file\n");
+ free(buffer);
+ return -1;
+ }
+
+ *size = length;
+ *data = buffer;
+ return 0;
+}
+
+void debug_plist(plist_t plist) {
+ int size = 0;
+ char* data = NULL;
+ plist_to_xml(plist, &data, &size);
+ info("%s", data);
+ free(data);
+}
+
+void print_progress_bar(double progress) {
+ int i = 0;
+ if(progress < 0) return;
+ if(progress > 100) progress = 100;
+ info("\r[");
+ for(i = 0; i < 50; i++) {
+ if(i < progress / 2) info("=");
+ else info(" ");
+ }
+ info("] %3.1f%%", progress);
+ if(progress == 100) info("\n");
+ fflush(stdout);
+}
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 0000000..cb774a5
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,151 @@
+/*
+ * common.h
+ * Misc functions used in idevicerestore
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef IDEVICERESTORE_COMMON_H
+#define IDEVICERESTORE_COMMON_H
+
+#include <plist/plist.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define info(...) printf(__VA_ARGS__)
+#define error(...) fprintf(stderr, __VA_ARGS__)
+#define debug(...) if(idevicerestore_debug) fprintf(stderr, __VA_ARGS__)
+
+#define CPID_UNKNOWN -1
+#define CPID_IPHONE2G 8900
+#define CPID_IPOD1G 8900
+#define CPID_IPHONE3G 8900
+#define CPID_IPOD2G 8720
+#define CPID_IPHONE3GS 8920
+#define CPID_IPOD3G 8922
+#define CPID_IPAD1G 8930
+
+#define BDID_UNKNOWN -1
+#define BDID_IPHONE2G 0
+#define BDID_IPOD1G 2
+#define BDID_IPHONE3G 4
+#define BDID_IPOD2G 0
+#define BDID_IPHONE3GS 0
+#define BDID_IPOD3G 2
+#define BDID_IPAD1G 2
+
+#define DEVICE_UNKNOWN -1
+#define DEVICE_IPHONE2G 0
+#define DEVICE_IPOD1G 1
+#define DEVICE_IPHONE3G 2
+#define DEVICE_IPOD2G 3
+#define DEVICE_IPHONE3GS 4
+#define DEVICE_IPOD3G 5
+#define DEVICE_IPAD1G 6
+
+#define MODE_UNKNOWN -1
+#define MODE_DFU 0
+#define MODE_RECOVERY 1
+#define MODE_RESTORE 2
+#define MODE_NORMAL 3
+
+#define FLAG_QUIT 1
+#define FLAG_DEBUG 2
+#define FLAG_ERASE 4
+#define FLAG_CUSTOM 8
+#define FLAG_EXCLUDE 16
+
+struct dfu_client_t;
+struct normal_client_t;
+struct restore_clien_t;
+struct recovery_client_t;
+
+struct idevicerestore_mode_t {
+ int index;
+ const char* string;
+};
+
+struct idevicerestore_entry_t {
+ char* name;
+ char* path;
+ char* filename;
+ char* blob_data;
+ uint32_t blob_size;
+ struct idevicerestore_entry* next;
+ struct idevicerestore_entry* prev;
+};
+
+struct idevicerestore_device_t {
+ int index;
+ const char* product;
+ const char* model;
+ uint32_t board_id;
+ uint32_t chip_id;
+};
+
+struct idevicerestore_client_t {
+ int flags;
+ plist_t tss;
+ uint64_t ecid;
+ const char* uuid;
+ const char* ipsw;
+ const char* filesystem;
+ struct dfu_client_t* dfu;
+ struct normal_client_t* normal;
+ struct restore_client_t* restore;
+ struct recovery_client_t* recovery;
+ struct idevicerestore_device_t* device;
+ struct idevicerestore_entry_t** entries;
+ struct idevicerestore_mode_t* mode;
+};
+
+static struct idevicerestore_mode_t idevicerestore_modes[] = {
+ { 0, "DFU" },
+ { 1, "Recovery" },
+ { 2, "Restore" },
+ { 3, "Normal" },
+ { -1, NULL }
+};
+
+static struct idevicerestore_device_t idevicerestore_devices[] = {
+ { 0, "iPhone1,1", "M68AP", 0, 8900 },
+ { 1, "iPod1,1", "N45AP", 2, 8900 },
+ { 2, "iPhone1,2", "N82AP", 4, 8900 },
+ { 3, "iPod2,1", "N72AP", 0, 8720 },
+ { 4, "iPhone2,1", "N88AP", 0, 8920 },
+ { 5, "iPod3,1", "N18AP", 2, 8922 },
+ { 6, "iPad1,1", "K48AP", 2, 8930 },
+ { 6, "iPhone3,1", "XXXAP", 0, 0 },
+ { -1, NULL, NULL, -1, -1 }
+};
+
+extern int idevicerestore_debug;
+
+void debug_plist(plist_t plist);
+void print_progress_bar(double progress);
+int read_file(const char* filename, void** data, size_t* size);
+int write_file(const char* filename, const void* data, size_t size);
+
+extern struct idevicerestore_client_t* idevicerestore;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/dfu.c b/src/dfu.c
index 1b0e8e7..b53803e 100644
--- a/src/dfu.c
+++ b/src/dfu.c
@@ -24,29 +24,87 @@
#include <libirecovery.h>
#include "dfu.h"
-#include "recovery.h"
+//#include "recovery.h"
#include "idevicerestore.h"
-int dfu_check_mode() {
- irecv_client_t dfu = NULL;
- irecv_error_t dfu_error = IRECV_E_SUCCESS;
+int dfu_progress_callback(irecv_client_t client, const irecv_event_t* event) {
+ if (event->type == IRECV_PROGRESS) {
+ print_progress_bar(event->progress);
+ }
+ return 0;
+}
- dfu_error = irecv_open(&dfu);
- if (dfu_error != IRECV_E_SUCCESS) {
+int dfu_client_new(struct idevicerestore_client_t* client, uint32_t timeout) {
+ struct dfu_client_t* dfu = NULL;
+ if(client == NULL) {
return -1;
}
- if (dfu->mode != kDfuMode) {
- irecv_close(dfu);
+ if(client->dfu) {
+ dfu_client_free(client);
+ }
+
+ dfu = (struct dfu_client_t*) malloc(sizeof(struct dfu_client_t));
+ if (dfu == NULL) {
+ error("ERROR: Out of memory\n");
return -1;
}
- irecv_close(dfu);
- dfu = NULL;
+ if (dfu_open_with_timeout(dfu, timeout) < 0) {
+ dfu_client_free(client);
+ return -1;
+ }
+
+ if(dfu->client->mode != kDfuMode) {
+ dfu_client_free(client);
+ return -1;
+ }
+
+ client->dfu = dfu;
+ return 0;
+}
+
+void dfu_client_free(struct idevicerestore_client_t* client) {
+ struct dfu_client_t* dfu = NULL;
+ if(client != NULL) {
+ dfu = client->dfu;
+ if (dfu != NULL) {
+ if(dfu->client != NULL) {
+ irecv_close(dfu->client);
+ dfu->client = NULL;
+ }
+ free(dfu);
+ }
+ client->dfu = NULL;
+ }
+}
+
+int dfu_open_with_timeout(struct idevicerestore_client_t* client, uint32_t timeout) {
+ int i = 0;
+ irecv_client_t recovery = NULL;
+ irecv_error_t recovery_error = IRECV_E_UNKNOWN_ERROR;
+
+ for (i = 1; i <= timeout; i++) {
+ recovery_error = irecv_open(&recovery);
+ if (recovery_error == IRECV_E_SUCCESS) {
+ break;
+ }
+
+ if (i == timeout) {
+ error("ERROR: Unable to connect to device in DFU mode\n");
+ return -1;
+ }
+
+ sleep(1);
+ debug("Retrying connection...\n");
+ }
+
+ irecv_event_subscribe(recovery, IRECV_PROGRESS, &dfu_progress_callback, NULL);
+ client->dfu = recovery;
return 0;
}
-int dfu_enter_recovery(const char* ipsw, plist_t tss) {
+int dfu_enter_recovery(struct idevicerestore_client_t* client) {
irecv_client_t dfu = NULL;
const char* component = "iBSS";
irecv_error_t dfu_error = IRECV_E_SUCCESS;
@@ -57,7 +115,7 @@ int dfu_enter_recovery(const char* ipsw, plist_t tss) {
return -1;
}
- if (recovery_send_signed_component(dfu, ipsw, tss, "iBSS") < 0) {
+ if (recovery_send_signed_component(dfu, client->ipsw, client->tss, "iBSS") < 0) {
error("ERROR: Unable to send %s to device\n", component);
irecv_close(dfu);
return -1;
@@ -80,7 +138,7 @@ int dfu_enter_recovery(const char* ipsw, plist_t tss) {
return -1;
}
- idevicerestore_mode = MODE_RECOVERY;
+ client->mode = &idevicerestore_modes[MODE_RECOVERY];
irecv_close(dfu);
dfu = NULL;
return 0;
diff --git a/src/dfu.h b/src/dfu.h
index 3577888..0e20448 100644
--- a/src/dfu.h
+++ b/src/dfu.h
@@ -22,10 +22,26 @@
#ifndef IDEVICERESTORE_DFU_H
#define IDEVICERESTORE_DFU_H
-#include <stdint.h>
-#include <plist/plist.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libirecovery.h>
+#include "common.h"
+
+struct dfu_client_t {
+ irecv_client_t client;
+ const char* ipsw;
+ plist_t tss;
+};
-int dfu_check_mode();
-int dfu_enter_recovery(const char* ipsw, plist_t tss);
+int dfu_client_new(struct idevicerestore_client_t* client, uint32_t timeout);
+void dfu_client_free(struct idevicerestore_client_t* client);
+int dfu_enter_recovery(struct idevicerestore_client_t* client);
+
+
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index c801266..cdbff27 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -25,38 +25,25 @@
#include <unistd.h>
#include <getopt.h>
#include <plist/plist.h>
-#include <libirecovery.h>
-#include <libimobiledevice/restore.h>
-#include <libimobiledevice/lockdown.h>
-#include <libimobiledevice/libimobiledevice.h>
-#include "dfu.h"
-#include "tss.h"
+#include "idevicerestore.h"
+//#include "recovery.h"
+#include "restore.h"
+#include "common.h"
+#include "normal.h"
#include "img3.h"
#include "ipsw.h"
-#include "normal.h"
-#include "restore.h"
-#include "recovery.h"
-#include "idevicerestore.h"
+#include "dfu.h"
+#include "tss.h"
-int idevicerestore_quit = 0;
-int idevicerestore_debug = 0;
-int idevicerestore_erase = 0;
-int idevicerestore_custom = 0;
-int idevicerestore_verbose = 0;
-int idevicerestore_exclude = 0;
-int idevicerestore_mode = MODE_UNKNOWN;
-idevicerestore_device_t* idevicerestore_device = NULL;
-
-static struct option long_opts[] = {
- { "uuid", required_argument, NULL, 'u' },
- { "debug", no_argument, NULL, 'd' },
- { "verbose", no_argument, NULL, 'v' },
- { "help", no_argument, NULL, 'h' },
- { "erase", no_argument, NULL, 'e' },
- { "custom", no_argument, NULL, 'c' },
- { "exclude", no_argument, NULL, 'x' },
- { NULL, 0, NULL, 0}
+static struct option longopts[] = {
+ { "uuid", required_argument, NULL, 'u' },
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "erase", no_argument, NULL, 'e' },
+ { "custom", no_argument, NULL, 'c' },
+ { "exclude", no_argument, NULL, 'x' },
+ { NULL, 0, NULL, 0 }
};
void usage(int argc, char* argv[]) {
@@ -65,7 +52,6 @@ void usage(int argc, char* argv[]) {
printf("Restore/upgrade IPSW firmware FILE to an iPhone/iPod Touch.\n");
printf(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n");
printf(" -d, --debug\t\tenable communication debugging\n");
- printf(" -v, --verbose\t\tenable verbose output\n");
printf(" -h, --help\t\tprints usage information\n");
printf(" -e, --erase\t\tperform a full restore, erasing all data\n");
printf(" -c, --custom\t\trestore with a custom firmware\n");
@@ -106,30 +92,36 @@ int main(int argc, char* argv[]) {
char* ipsw = NULL;
char* uuid = NULL;
uint64_t ecid = 0;
- while ((opt = getopt_long(argc, argv, "vdhcexu:", long_opts, &optindex)) > 0) {
+
+ // create an instance of our context
+ struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) malloc(sizeof(struct idevicerestore_client_t));
+ if (client == NULL) {
+ error("ERROR: Out of memory\n");
+ return -1;
+ }
+ memset(client, '\0', sizeof(struct idevicerestore_client_t));
+ idevicerestore = client;
+
+ while ((opt = getopt_long(argc, argv, "dhcexu:", longopts, &optindex)) > 0) {
switch (opt) {
case 'h':
usage(argc, argv);
break;
case 'd':
- idevicerestore_debug = 1;
+ client->flags &= FLAG_DEBUG;
break;
case 'e':
- idevicerestore_erase = 1;
+ client->flags &= FLAG_ERASE;
break;
case 'c':
- idevicerestore_custom = 1;
+ client->flags &= FLAG_CUSTOM;
break;
case 'x':
- idevicerestore_exclude = 1;
- break;
-
- case 'v':
- idevicerestore_verbose = 1;
+ client->flags &= FLAG_EXCLUDE;
break;
case 'u':
@@ -152,27 +144,30 @@ int main(int argc, char* argv[]) {
return -1;
}
- if(idevicerestore_debug) {
- idevice_set_debug_level(5);
+ if (client->flags & FLAG_DEBUG) {
+ idevice_set_debug_level(1);
+ irecv_set_debug_level(1);
}
+ client->uuid = uuid;
+ client->ipsw = ipsw;
+
// check which mode the device is currently in so we know where to start
- idevicerestore_mode = check_mode(uuid);
- if (idevicerestore_mode < 0) {
+ if (check_mode(client) < 0 || client->mode->index == MODE_UNKNOWN) {
error("ERROR: Unable to discover current device state\n");
return -1;
}
+ info("Found device in %s mode\n", client->mode->string);
// discover the device type
- int id = check_device(uuid);
- if (id < 0) {
+ if (check_device(client) < 0 || client->device->index == DEVICE_UNKNOWN) {
error("ERROR: Unable to discover device type\n");
return -1;
}
- idevicerestore_device = &idevicerestore_devices[id];
+ info("Identified device as %s\n", client->device->product);
- if (idevicerestore_mode == MODE_RESTORE) {
- if (restore_reboot(uuid) < 0) {
+ if (client->mode->index == MODE_RESTORE) {
+ if (restore_reboot(client) < 0) {
error("ERROR: Unable to exit restore mode\n");
return -1;
}
@@ -181,28 +176,28 @@ int main(int argc, char* argv[]) {
// extract buildmanifest
plist_t buildmanifest = NULL;
info("Extracting BuildManifest from IPSW\n");
- if (extract_buildmanifest(ipsw, &buildmanifest) < 0) {
+ if (extract_buildmanifest(client, ipsw, &buildmanifest) < 0) {
error("ERROR: Unable to extract BuildManifest from %s\n", ipsw);
return -1;
}
// devices are listed in order from oldest to newest
// so we'll need their ECID
- if (idevicerestore_device->device_id > DEVICE_IPOD2G) {
- info("Creating TSS request\n");
+ if (client->device->index > DEVICE_IPOD2G) {
+ debug("Creating TSS request\n");
// fetch the device's ECID for the TSS request
- if (get_ecid(uuid, &ecid) < 0 || ecid == 0) {
+ if (get_ecid(client, &client->ecid) < 0) {
error("ERROR: Unable to find device ECID\n");
return -1;
}
- debug("Found ECID %llu\n", ecid);
+ debug("Found ECID %llu\n", client->ecid);
}
// choose whether this is an upgrade or a restore (default to upgrade)
plist_t tss = NULL;
plist_t build_identity = NULL;
- if (idevicerestore_erase) {
- build_identity = get_build_identity(buildmanifest, 0);
+ if (client->flags & FLAG_ERASE) {
+ build_identity = get_build_identity(client, buildmanifest, 0);
if (build_identity == NULL) {
error("ERROR: Unable to find build any identities\n");
plist_free(buildmanifest);
@@ -215,9 +210,10 @@ int main(int argc, char* argv[]) {
int i = 0;
int valid_builds = 0;
int build_count = get_build_count(buildmanifest);
- for(i = 0; i < build_count; i++) {
- if (idevicerestore_device->device_id > DEVICE_IPOD2G) {
- if (get_shsh_blobs(ecid, buildmanifest, &tss) < 0) {
+ for (i = 0; i < build_count; i++) {
+ if (client->device->index > DEVICE_IPOD2G) {
+ build_identity = get_build_identity(client, buildmanifest, i);
+ if (get_shsh_blobs(client, ecid, build_identity, &tss) < 0) {
// if this fails then no SHSH blobs have been saved
// for this build identity, so check the next one
continue;
@@ -231,29 +227,29 @@ int main(int argc, char* argv[]) {
// devices are listed in order from oldest to newest
// devices that come after iPod2g require personalized firmwares
plist_t tss_request = NULL;
- if (idevicerestore_device->device_id > DEVICE_IPOD2G) {
+ if (client->device->index > DEVICE_IPOD2G) {
info("Creating TSS request\n");
// fetch the device's ECID for the TSS request
- if (get_ecid(uuid, &ecid) < 0 || ecid == 0) {
+ if (get_ecid(client, &ecid) < 0 || ecid == 0) {
error("ERROR: Unable to find device ECID\n");
return -1;
}
- info("Found ECID %llu\n", ecid);
+ debug("Found ECID %llu\n", ecid);
// fetch the SHSH blobs for this build identity
- if (get_shsh_blobs(ecid, build_identity, &tss) < 0) {
+ if (get_shsh_blobs(client, ecid, build_identity, &tss) < 0) {
// this might fail if the TSS server doesn't have the saved blobs for the
// update identity, so go ahead and try again with the restore identity
- if (idevicerestore_erase != 1) {
+ if (client->flags & FLAG_ERASE > 0) {
info("Unable to fetch SHSH blobs for upgrade, retrying with full restore\n");
- build_identity = get_build_identity(buildmanifest, 0);
+ build_identity = get_build_identity(client, buildmanifest, 0);
if (build_identity == NULL) {
error("ERROR: Unable to find restore identity\n");
plist_free(buildmanifest);
return -1;
}
- if (get_shsh_blobs(ecid, build_identity, &tss) < 0) {
+ if (get_shsh_blobs(client, ecid, build_identity, &tss) < 0) {
// if this fails then no SHSH blobs have been saved for this firmware
error("ERROR: Unable to fetch SHSH blobs for this firmware\n");
plist_free(buildmanifest);
@@ -270,7 +266,7 @@ int main(int argc, char* argv[]) {
// Extract filesystem from IPSW and return its name
char* filesystem = NULL;
- if (extract_filesystem(ipsw, build_identity, &filesystem) < 0) {
+ if (extract_filesystem(client, ipsw, build_identity, &filesystem) < 0) {
error("ERROR: Unable to extract filesystem from IPSW\n");
if (tss)
plist_free(tss);
@@ -279,7 +275,7 @@ int main(int argc, char* argv[]) {
}
// if the device is in normal mode, place device into recovery mode
- if (idevicerestore_mode == MODE_NORMAL) {
+ if (client->mode->index == MODE_NORMAL) {
info("Entering recovery mode...\n");
if (normal_enter_recovery(uuid) < 0) {
error("ERROR: Unable to place device into recovery mode\n");
@@ -291,8 +287,8 @@ int main(int argc, char* argv[]) {
}
// if the device is in DFU mode, place device into recovery mode
- if (idevicerestore_mode == MODE_DFU) {
- if (dfu_enter_recovery(ipsw, tss) < 0) {
+ if (client->mode->index == MODE_DFU) {
+ if (dfu_enter_recovery(client) < 0) {
error("ERROR: Unable to place device into recovery mode\n");
plist_free(buildmanifest);
if (tss)
@@ -302,7 +298,7 @@ int main(int argc, char* argv[]) {
}
// if the device is in recovery mode, place device into restore mode
- if (idevicerestore_mode == MODE_RECOVERY) {
+ if (client->mode->index == MODE_RECOVERY) {
if (recovery_enter_restore(uuid, ipsw, tss) < 0) {
error("ERROR: Unable to place device into restore mode\n");
plist_free(buildmanifest);
@@ -313,16 +309,16 @@ int main(int argc, char* argv[]) {
}
// device is finally in restore mode, let's do this
- if (idevicerestore_mode == MODE_RESTORE) {
+ if (client->mode->index == MODE_RESTORE) {
info("Restoring device... \n");
- if (restore_device(uuid, ipsw, tss, filesystem) < 0) {
+ if (restore_device(client, uuid, ipsw, tss, filesystem) < 0) {
error("ERROR: Unable to restore device\n");
return -1;
}
}
// device has finished restoring, lets see if we need to activate
- if (idevicerestore_mode == MODE_NORMAL) {
+ if (client->mode->index == MODE_NORMAL) {
info("Checking activation status\n");
int activation = activate_check_status(uuid);
if (activation < 0) {
@@ -347,7 +343,7 @@ int main(int argc, char* argv[]) {
return 0;
}
-int check_mode(const char* uuid) {
+int check_mode(struct idevicerestore_client_t* client) {
int mode = MODE_UNKNOWN;
if (recovery_check_mode() == 0) {
@@ -360,34 +356,35 @@ int check_mode(const char* uuid) {
mode = MODE_DFU;
}
- else if (normal_check_mode(uuid) == 0) {
+ else if (normal_check_mode(client->uuid) == 0) {
info("Found device in normal mode\n");
mode = MODE_NORMAL;
}
- else if (restore_check_mode(uuid) == 0) {
+ else if (restore_check_mode(client->uuid) == 0) {
info("Found device in restore mode\n");
mode = MODE_RESTORE;
}
+ client->mode = &idevicerestore_modes[mode];
return mode;
}
-int check_device(const char* uuid) {
+int check_device(struct idevicerestore_client_t* client) {
int device = DEVICE_UNKNOWN;
uint32_t bdid = 0;
uint32_t cpid = 0;
- switch (idevicerestore_mode) {
+ switch (client->mode->index) {
case MODE_RESTORE:
- device = restore_check_device(uuid);
+ device = restore_check_device(client->uuid);
if (device < 0) {
device = DEVICE_UNKNOWN;
}
break;
case MODE_NORMAL:
- device = normal_check_device(uuid);
+ device = normal_check_device(client->uuid);
if (device < 0) {
device = DEVICE_UNKNOWN;
}
@@ -395,7 +392,7 @@ int check_device(const char* uuid) {
case MODE_DFU:
case MODE_RECOVERY:
- if (get_cpid(uuid, &cpid) < 0) {
+ if (get_cpid(client, &cpid) < 0) {
error("ERROR: Unable to get device CPID\n");
break;
}
@@ -404,7 +401,7 @@ int check_device(const char* uuid) {
case CPID_IPHONE2G:
// iPhone1,1 iPhone1,2 and iPod1,1 all share the same ChipID
// so we need to check the BoardID
- if (get_bdid(uuid, &bdid) < 0) {
+ if (get_bdid(client, &bdid) < 0) {
error("ERROR: Unable to get device BDID\n");
break;
}
@@ -456,22 +453,23 @@ int check_device(const char* uuid) {
}
+ client->device = &idevicerestore_devices[device];
return device;
}
-int get_bdid(const char* uuid, uint32_t* bdid) {
- switch (idevicerestore_mode) {
+int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) {
+ switch (client->mode->index) {
case MODE_NORMAL:
- if (normal_get_bdid(uuid, bdid) < 0) {
- *bdid = -1;
+ if (normal_get_bdid(client->uuid, &client->device->board_id) < 0) {
+ client->device->board_id = -1;
return -1;
}
break;
case MODE_DFU:
case MODE_RECOVERY:
- if (recovery_get_bdid(bdid) < 0) {
- *bdid = -1;
+ if (recovery_get_bdid(&client->device->board_id) < 0) {
+ client->device->board_id = -1;
return -1;
}
break;
@@ -484,19 +482,19 @@ int get_bdid(const char* uuid, uint32_t* bdid) {
return 0;
}
-int get_cpid(const char* uuid, uint32_t* cpid) {
- switch (idevicerestore_mode) {
+int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) {
+ switch (client->mode->index) {
case MODE_NORMAL:
- if (normal_get_cpid(uuid, cpid) < 0) {
- *cpid = 0;
+ if (normal_get_cpid(client->uuid, &client->device->chip_id) < 0) {
+ client->device->chip_id = -1;
return -1;
}
break;
case MODE_DFU:
case MODE_RECOVERY:
- if (recovery_get_cpid(cpid) < 0) {
- *cpid = 0;
+ if (recovery_get_cpid(&client->device->chip_id) < 0) {
+ client->device->chip_id = -1;
return -1;
}
break;
@@ -509,10 +507,15 @@ int get_cpid(const char* uuid, uint32_t* cpid) {
return 0;
}
-int get_ecid(const char* uuid, uint64_t* ecid) {
- switch (idevicerestore_mode) {
+int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) {
+ if(client->device->index <= DEVICE_IPOD2G) {
+ *ecid = 0;
+ return 0;
+ }
+
+ switch (client->mode->index) {
case MODE_NORMAL:
- if (normal_get_ecid(uuid, ecid) < 0) {
+ if (normal_get_ecid(client->uuid, ecid) < 0) {
*ecid = 0;
return -1;
}
@@ -534,10 +537,10 @@ int get_ecid(const char* uuid, uint64_t* ecid) {
return 0;
}
-int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) {
+int extract_buildmanifest(struct idevicerestore_client_t* client, const char* ipsw, plist_t* buildmanifest) {
int size = 0;
char* data = NULL;
- int device = idevicerestore_device->device_id;
+ int device = client->device->index;
if (device >= DEVICE_IPHONE2G && device <= DEVICE_IPOD2G) {
// Older devices that don't require personalized firmwares use BuildManifesto.plist
if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) < 0) {
@@ -558,7 +561,7 @@ int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) {
return 0;
}
-plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) {
+plist_t get_build_identity(struct idevicerestore_client_t* client, plist_t buildmanifest, uint32_t identity) {
// fetch build identities array from BuildManifest
plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities");
if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) {
@@ -580,7 +583,7 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) {
return plist_copy(build_identity);
}
-int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) {
+int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, plist_t build_identity, plist_t* tss) {
plist_t request = NULL;
plist_t response = NULL;
*tss = NULL;
@@ -603,7 +606,33 @@ int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) {
return 0;
}
-int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) {
+int get_build_count(plist_t buildmanifest) {
+ // fetch build identities array from BuildManifest
+ plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities");
+ if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) {
+ error("ERROR: Unable to find build identities node\n");
+ return -1;
+ }
+
+ // check and make sure this identity exists in buildmanifest
+ return plist_array_get_size(build_identities_array);
+}
+
+const char* get_build_name(plist_t build_identity, int identity) {
+ plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest");
+ if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
+ error("ERROR: Unable to find restore manifest\n");
+ return NULL;
+ }
+
+ plist_t filesystem_info_node = plist_dict_get_item(manifest_node, "Info");
+ if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) {
+ error("ERROR: Unable to find filesystem info node\n");
+ return NULL;
+ }
+}
+
+int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t build_identity, char** filesystem) {
char* filename = NULL;
plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest");
@@ -641,7 +670,7 @@ int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesyst
return 0;
}
-int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) {
+int get_signed_component(struct idevicerestore_client_t* client, const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) {
img3_file* img3 = NULL;
uint32_t component_size = 0;
char* component_data = NULL;
@@ -649,8 +678,10 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char**
char* component_name = NULL;
component_name = strrchr(path, '/');
- if (component_name != NULL) component_name++;
- else component_name = (char*) path;
+ if (component_name != NULL)
+ component_name++;
+ else
+ component_name = (char*) path;
info("Extracting %s\n", component_name);
if (ipsw_extract_to_memory(ipsw, path, &component_data, &component_size) < 0) {
@@ -672,7 +703,7 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char**
return -1;
}
- if (idevicerestore_device->device_id > DEVICE_IPOD2G && idevicerestore_custom == 0) {
+ if (client->device->index > DEVICE_IPOD2G && (client->flags & FLAG_CUSTOM) == 0) {
if (img3_replace_signature(img3, component_blob) < 0) {
error("ERROR: Unable to replace IMG3 signature\n");
free(component_blob);
@@ -689,7 +720,7 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char**
}
img3_free(img3);
- if (idevicerestore_debug) {
+ if (client->flags & FLAG_DEBUG) {
write_file(component_name, component_data, component_size);
}
@@ -697,66 +728,3 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char**
*size = component_size;
return 0;
}
-
-int write_file(const char* filename, const void* data, size_t size) {
- size_t bytes = 0;
- FILE* file = NULL;
-
- info("Writing data to %s\n", filename);
- file = fopen(filename, "wb");
- if (file == NULL) {
- error("read_file: Unable to open file %s\n", filename);
- return -1;
- }
-
- bytes = fwrite(data, 1, size, file);
- fclose(file);
-
- if (bytes != size) {
- error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size);
- return -1;
- }
-
- return size;
-}
-
-int read_file(const char* filename, char** data, uint32_t* size) {
- size_t bytes = 0;
- size_t length = 0;
- FILE* file = NULL;
- char* buffer = NULL;
- debug("Reading data from %s\n", filename);
-
- *size = 0;
- *data = NULL;
-
- file = fopen(filename, "rb");
- if (file == NULL) {
- error("read_file: File %s not found\n", filename);
- return -1;
- }
-
- fseek(file, 0, SEEK_END);
- length = ftell(file);
- rewind(file);
-
- buffer = (char*) malloc(length);
- if(buffer == NULL) {
- error("ERROR: Out of memory\n");
- fclose(file);
- return -1;
- }
- bytes = fread(buffer, 1, length, file);
- fclose(file);
-
- if(bytes != length) {
- error("ERROR: Unable to read entire file\n");
- free(buffer);
- return -1;
- }
-
- *size = length;
- *data = buffer;
- return 0;
-}
-
diff --git a/src/idevicerestore.h b/src/idevicerestore.h
index 20578a9..7e5873b 100644
--- a/src/idevicerestore.h
+++ b/src/idevicerestore.h
@@ -22,135 +22,31 @@
#ifndef IDEVICERESTORE_H
#define IDEVICERESTORE_H
-#include <stdio.h>
-#include <stdlib.h>
-#include <plist/plist.h>
-
-#define info(...) printf(__VA_ARGS__)
-#define error(...) fprintf(stderr, __VA_ARGS__)
-#define debug(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__)
-
-#define MODE_UNKNOWN -1
-#define MODE_DFU 0
-#define MODE_RECOVERY 1
-#define MODE_RESTORE 2
-#define MODE_NORMAL 3
-
-#define CPID_UNKNOWN -1
-#define CPID_IPHONE2G 8900
-#define CPID_IPOD1G 8900
-#define CPID_IPHONE3G 8900
-#define CPID_IPOD2G 8720
-#define CPID_IPHONE3GS 8920
-#define CPID_IPOD3G 8922
-#define CPID_IPAD1G 8930
-
-#define BDID_UNKNOWN -1
-#define BDID_IPHONE2G 0
-#define BDID_IPOD1G 2
-#define BDID_IPHONE3G 4
-#define BDID_IPOD2G 0
-#define BDID_IPHONE3GS 0
-#define BDID_IPOD3G 2
-#define BDID_IPAD1G 2
-
-#define DEVICE_UNKNOWN -1
-#define DEVICE_IPHONE2G 0
-#define DEVICE_IPOD1G 1
-#define DEVICE_IPHONE3G 2
-#define DEVICE_IPOD2G 3
-#define DEVICE_IPHONE3GS 4
-#define DEVICE_IPOD3G 5
-#define DEVICE_IPAD1G 6
-
-typedef struct idevicerestore_entry {
- char* name;
- char* path;
- char* filename;
- char* blob_data;
- uint32_t blob_size;
- struct idevicerestore_entry* next;
- struct idevicerestore_entry* prev;
-} idevicerestore_entry_t;
+#ifdef __cplusplus
+extern "C" {
+#endif
-typedef struct {
- int device_id;
- const char* product;
- const char* model;
- int board_id;
- int chip_id;
-} idevicerestore_device_t;
-/*
-typedef struct {
- int mode;
- idevice_t device;
- irecv_client_t recovery;
- restored_client_t restore;
- lockdownd_client_t lockdown;
- int erase; // 1
- int custom; // 2
- int exclude; // 4
- int verbose; // 8
- idevicerestore_device_t* idevicerestore_device;
- idevicerestore_entry_t** entries;
-} idevicerestore_context_t;
-*/
-static idevicerestore_device_t idevicerestore_devices[] = {
- { 0, "iPhone1,1", "M68AP", 0, 8900 },
- { 1, "iPod1,1", "N45AP", 2, 8900 },
- { 2, "iPhone1,2", "N82AP", 4, 8900 },
- { 3, "iPod2,1", "N72AP", 0, 8720 },
- { 4, "iPhone2,1", "N88AP", 0, 8920 },
- { 5, "iPod3,1", "N18AP", 2, 8922 },
- { 6, "iPad1,1", "K48AP", 2, 8930 },
- { 6, "iPhone4,1", "XXXAP", 0, 0 },
- { -1, NULL, NULL, -1, -1 }
-};
+#include <stdint.h>
+#include <plist/plist.h>
-extern int idevicerestore_mode;
-extern int idevicerestore_quit;
-extern int idevicerestore_debug;
-extern int idevicerestore_erase;
-extern int idevicerestore_custom;
-extern int idevicerestore_exclude;
-extern int idevicerestore_verbose;
-extern idevicerestore_device_t* idevicerestore_device;
-extern idevicerestore_entry_t** idevicerestore_entries;
+#include <plist/plist.h>
+#include "common.h"
-int check_mode(const char* uuid);
-int check_device(const char* uuid);
void usage(int argc, char* argv[]);
-int get_ecid(const char* uuid, uint64_t* ecid);
-int get_bdid(const char* uuid, uint32_t* bdid);
-int get_cpid(const char* uuid, uint32_t* cpid);
-int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest);
-plist_t get_build_identity(plist_t buildmanifest, uint32_t identity);
-int write_file(const char* filename, const void* data, size_t size);
-int read_file(const char* filename, char** data, uint32_t* size);
-int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss);
-int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem);
-int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size);
-
-inline static void debug_plist(plist_t plist) {
- int size = 0;
- char* data = NULL;
- plist_to_xml(plist, &data, &size);
- debug("%s", data);
- free(data);
-}
-
-inline static void print_progress_bar(const char* operation, double progress) {
- int i = 0;
- if(progress < 0) return;
- if(progress > 100) progress = 100;
- info("\r%s [", operation);
- for(i = 0; i < 50; i++) {
- if(i < progress / 2) info("=");
- else info(" ");
- }
- info("] %3.1f%%", progress);
- if(progress == 100) info("\n");
- fflush(stdout);
+int check_mode(struct idevicerestore_client_t* client);
+int check_device(struct idevicerestore_client_t* client);
+const char* get_build_name(plist_t build_identity, int identity);
+int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);
+int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid);
+int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid);
+int extract_buildmanifest(struct idevicerestore_client_t* client, const char* ipsw, plist_t* buildmanifest);
+plist_t get_build_identity(struct idevicerestore_client_t* client, plist_t buildmanifest, uint32_t identity);
+int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, plist_t build_identity, plist_t* tss);
+int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t buildmanifest, char** filesystem);
+int get_signed_component(struct idevicerestore_client_t* client, const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size);
+
+#ifdef __cplusplus
}
+#endif
#endif
diff --git a/src/img3.h b/src/img3.h
index 5fddbfc..796a8e1 100644
--- a/src/img3.h
+++ b/src/img3.h
@@ -22,6 +22,10 @@
#ifndef IDEVICERESTORE_IMG3_H
#define IDEVICERESTORE_IMG3_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef enum {
kNorContainer = 0x696D6733, // img3
kImg3Container = 0x496D6733, // Img3
@@ -86,4 +90,9 @@ img3_file* img3_parse_file(char* data, int size);
int img3_get_data(img3_file* image, char** pdata, int* psize);
int img3_replace_signature(img3_file* image, char* signature);
+
+#ifdef __cplusplus
+}s
+#endif
+
#endif
diff --git a/src/ipsw.c b/src/ipsw.c
index adbaea0..f08e2fd 100644
--- a/src/ipsw.c
+++ b/src/ipsw.c
@@ -114,7 +114,7 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi
bytes += size;
progress = ((double) bytes/ (double) zstat.size) * 100.0;
- print_progress_bar("Extracting", progress);
+ print_progress_bar(progress);
}
fclose(fd);
diff --git a/src/ipsw.h b/src/ipsw.h
index aa0fd1d..cd11406 100644
--- a/src/ipsw.h
+++ b/src/ipsw.h
@@ -22,6 +22,10 @@
#ifndef IDEVICERESTORE_IPSW_H
#define IDEVICERESTORE_IPSW_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <zip.h>
#include <stdint.h>
@@ -35,4 +39,8 @@ typedef struct {
int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, uint32_t* psize);
void ipsw_free_file(ipsw_file* file);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/src/normal.c b/src/normal.c
index b9270d8..7ae4774 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -25,9 +25,49 @@
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/libimobiledevice.h>
+#include "common.h"
#include "normal.h"
-#include "recovery.h"
-#include "idevicerestore.h"
+//#include "recovery.h"
+
+int normal_client_new(struct normal_client_t** normal) {
+ struct normal_client_t* client = (struct normal_client_t*) malloc(sizeof(struct normal_client_t));
+ if (client == NULL) {
+ error("ERROR: Out of memory\n");
+ return -1;
+ }
+
+ if (normal_open_with_timeout(client) < 0) {
+ normal_client_free(client);
+ return -1;
+ }
+
+ if(normal_check_mode(client) < 0) {
+ normal_client_free(client);
+ return -1;
+ }
+
+ *normal = client;
+ return client;
+}
+
+void normal_client_free(struct idevicerestore_client_t* client) {
+ struct normal_client_t* normal = NULL;
+ if (client) {
+ normal = client->normal;
+ if(normal) {
+ if(normal->client) {
+ lockdownd_client_free(normal->client);
+ normal->client = NULL;
+ }
+ if(normal->device) {
+ idevice_free(normal->device);
+ normal->device = NULL;
+ }
+ }
+ free(normal);
+ client->normal = NULL;
+ }
+}
int normal_check_mode(const char* uuid) {
char* type = NULL;
@@ -106,7 +146,7 @@ int normal_check_device(const char* uuid) {
}
}
- return idevicerestore_devices[i].device_id;
+ return idevicerestore_devices[i].index;
}
int normal_enter_recovery(const char* uuid) {
@@ -162,7 +202,7 @@ int normal_enter_recovery(const char* uuid) {
return -1;
}
- idevicerestore_mode = MODE_RECOVERY;
+ //client->mode = &idevicerestore_modes[MODE_RECOVERY];
irecv_close(recovery);
recovery = NULL;
return 0;
diff --git a/src/normal.h b/src/normal.h
index cdc29ba..352e643 100644
--- a/src/normal.h
+++ b/src/normal.h
@@ -22,7 +22,20 @@
#ifndef IDEVICERESTORE_NORMAL_H
#define IDEVICERESTORE_NORMAL_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <stdint.h>
+#include <libimobiledevice/lockdown.h>
+#include <libimobiledevice/libimobiledevice.h>
+
+struct normal_client_t {
+ idevice_t device;
+ lockdownd_client_t client;
+ const char* ipsw;
+ plist_t tss;
+};
int normal_check_mode(const char* uuid);
int normal_check_device(const char* uuid);
@@ -31,4 +44,8 @@ int normal_get_cpid(const char* uuid, uint32_t* cpid);
int normal_get_bdid(const char* uuid, uint32_t* cpid);
int normal_get_ecid(const char* uuid, uint64_t* ecid);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/src/recovery.c b/src/recovery.c
index 88d385f..bacfac7 100644
--- a/src/recovery.c
+++ b/src/recovery.c
@@ -28,16 +28,51 @@
#include "tss.h"
#include "img3.h"
+#include "common.h"
#include "recovery.h"
#include "idevicerestore.h"
int recovery_progress_callback(irecv_client_t client, const irecv_event_t* event) {
if (event->type == IRECV_PROGRESS) {
- print_progress_bar(event->data, event->progress);
+ print_progress_bar(event->progress);
}
return 0;
}
+int recovery_client_new(struct idevicerestore_client_t* client) {
+ struct recovery_client_t* recovery = (struct recovery_client_t*) malloc(sizeof(struct recovery_client_t));
+ if (recovery == NULL) {
+ error("ERROR: Out of memory\n");
+ return -1;
+ }
+
+ if (recovery_open_with_timeout(recovery) < 0) {
+ recovery_client_free(recovery);
+ return -1;
+ }
+
+ if(recovery_check_mode(recovery) < 0) {
+ recovery_client_free(recovery);
+ return -1;
+ }
+
+ client->recovery = recovery;
+ return 0;
+}
+
+void recovery_client_free(struct idevicerestore_client_t* client) {
+ struct recovery_client_t* recovery = client->recovery;
+ if (recovery) {
+ if(recovery->client) {
+ irecv_close(recovery);
+ recovery = NULL;
+ }
+ free(recovery);
+ client->recovery = NULL;
+
+ }
+}
+
int recovery_check_mode() {
irecv_client_t recovery = NULL;
irecv_error_t recovery_error = IRECV_E_SUCCESS;
@@ -101,11 +136,11 @@ int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss) {
}
restore_close(device, restore);
- idevicerestore_mode = MODE_RESTORE;
+ client->mode = &idevicerestore_modes[MODE_RESTORE];
return 0;
}
-int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component) {
+int recovery_send_signed_component(struct idevicerestore_client_t client, const char* ipsw, plist_t tss, char* component) {
int size = 0;
char* data = NULL;
char* path = NULL;
@@ -117,7 +152,7 @@ int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plis
return -1;
}
- if (get_signed_component(ipsw, tss, path, &data, &size) < 0) {
+ if (get_signed_component(client, ipsw, tss, path, &data, &size) < 0) {
error("ERROR: Unable to get signed component: %s\n", component);
free(path);
return -1;
@@ -157,10 +192,6 @@ int recovery_open_with_timeout(irecv_client_t* client) {
debug("Retrying connection...\n");
}
- if (idevicerestore_debug) {
- irecv_set_debug_level(idevicerestore_debug);
- }
-
irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL);
*client = recovery;
return 0;
diff --git a/src/recovery.h b/src/recovery.h
index 1953c6a..6cd467c 100644
--- a/src/recovery.h
+++ b/src/recovery.h
@@ -22,12 +22,24 @@
#ifndef IDEVICERESTORE_RECOVERY_H
#define IDEVICERESTORE_RECOVERY_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <stdint.h>
#include <plist/plist.h>
+#include <libirecovery.h>
+
+struct recovery_client_t {
+ irecv_client_t client;
+ const char* ipsw;
+ plist_t tss;
+};
int recovery_check_mode();
-int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss);
-int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component);
+int recovery_client_new(struct idevicerestore_client_t* client);
+void recovery_client_free(struct idevicerestore_client_t* client);
+int recovery_send_signed_component(struct idevicerestore_client_t* client, const char* ipsw, plist_t tss, char* component) {
irecv_error_t recovery_open_with_timeout(irecv_client_t* client);
int recovery_send_ibec(const char* ipsw, plist_t tss);
int recovery_send_applelogo(const char* ipsw, plist_t tss);
@@ -38,4 +50,8 @@ int recovery_get_ecid(uint64_t* ecid);
int recovery_get_cpid(uint32_t* cpid);
int recovery_get_bdid(uint32_t* bdid);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/src/restore.c b/src/restore.c
index fa2ccdd..b4cf0b2 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -26,8 +26,8 @@
#include "asr.h"
#include "tss.h"
+#include "common.h"
#include "restore.h"
-#include "idevicerestore.h"
#define CREATE_PARTITION_MAP 12
#define CREATE_FILESYSTEM 13
@@ -46,6 +46,39 @@
static int restore_device_connected = 0;
+int restore_client_new(struct idevicerestore_client_t* client) {
+ struct restore_client_t* restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t));
+ if (restore == NULL) {
+ error("ERROR: Out of memory\n");
+ return -1;
+ }
+
+ if (restore_open_with_timeout(client) < 0) {
+ restore_client_free(client);
+ return -1;
+ }
+
+ client->restore = restore;
+ return 0;
+}
+
+void restore_client_free(struct idevicerestore_client_t* client) {
+ if (client) {
+ if(client->restore) {
+ if(client->restore->client) {
+ restored_client_free(client->restore->client);
+ client->restore->client = NULL;
+ }
+ if(client->restore->device) {
+ idevice_free(client->restore->device);
+ client->restore->device = NULL;
+ }
+ free(client->restore);
+ client->restore = NULL;
+ }
+ }
+}
+
int restore_check_mode(const char* uuid) {
char* type = NULL;
uint64_t version = 0;
@@ -135,51 +168,61 @@ int restore_check_device(const char* uuid) {
}
}
- return idevicerestore_devices[i].device_id;
+ return idevicerestore_devices[i].index;
}
-void restore_device_callback(const idevice_event_t* event, void* user_data) {
+void restore_device_callback(const idevice_event_t* event, void* userdata) {
+ struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) userdata;
if (event->event == IDEVICE_DEVICE_ADD) {
restore_device_connected = 1;
} else if (event->event == IDEVICE_DEVICE_REMOVE) {
restore_device_connected = 0;
- idevicerestore_quit = 1;
+ client->flags &= FLAG_QUIT;
}
}
-int restore_reboot(const char* uuid) {
+int restore_reboot(struct idevicerestore_client_t* client) {
idevice_t device = NULL;
restored_client_t restore = NULL;
restored_error_t restore_error = RESTORE_E_SUCCESS;
- if (restore_open_with_timeout(uuid, &device, &restore) < 0) {
- error("ERROR: Unable to open device in restore mode\n");
- return -1;
+ if(!client->restore) {
+ if (restore_open_with_timeout(client) < 0) {
+ error("ERROR: Unable to open device in restore mode\n");
+ return -1;
+ }
}
- restore_error = restored_reboot(restore);
+ restore_error = restored_reboot(client);
if (restore_error != RESTORE_E_SUCCESS) {
error("ERROR: Unable to reboot the device from restore mode\n");
- restore_close(device, restore);
return -1;
}
- restore_close(device, restore);
- restore = NULL;
- device = NULL;
return 0;
}
-int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* restore) {
+int restore_open_with_timeout(struct idevicerestore_client_t* client) {
int i = 0;
int attempts = 10;
- idevice_t context = NULL;
- restored_client_t client = NULL;
+ idevice_t device = NULL;
+ restored_client_t restored = NULL;
idevice_error_t device_error = IDEVICE_E_SUCCESS;
restored_error_t restore_error = RESTORE_E_SUCCESS;
- *device = NULL;
- *restore = NULL;
+ // no context exists so bail
+ if(client == NULL) {
+ return -1;
+ }
+
+ // create our restore client if it doesn't yet exist
+ if(client->restore == NULL) {
+ client->restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t));
+ if(client->restore == NULL) {
+ error("ERROR: Out of memory\n");
+ return -1;
+ }
+ }
device_error = idevice_event_subscribe(&restore_device_callback, NULL);
if (device_error != IDEVICE_E_SUCCESS) {
@@ -194,43 +237,37 @@ int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_clie
if (i == attempts) {
error("ERROR: Unable to connect to device in restore mode\n");
+ return -1;
}
sleep(2);
}
- device_error = idevice_new(&context, uuid);
+ device_error = idevice_new(&device, client->uuid);
if (device_error != IDEVICE_E_SUCCESS) {
return -1;
}
- restore_error = restored_client_new(context, &client, "idevicerestore");
+ restore_error = restored_client_new(device, &restored, "idevicerestore");
if (restore_error != RESTORE_E_SUCCESS) {
- idevice_event_unsubscribe();
- idevice_free(context);
+ //idevice_event_unsubscribe();
+ idevice_free(device);
return -1;
}
- restore_error = restored_query_type(client, NULL, NULL);
+ restore_error = restored_query_type(restored, NULL, NULL);
if (restore_error != RESTORE_E_SUCCESS) {
- restored_client_free(client);
- idevice_event_unsubscribe();
- idevice_free(context);
+ restored_client_free(restored);
+ //idevice_event_unsubscribe();
+ idevice_free(device);
return -1;
}
- *device = context;
- *restore = client;
+ client->restore->device = device;
+ client->restore->client = restored;
return 0;
}
-void restore_close(idevice_t device, restored_client_t restore) {
- if (restore)
- restored_client_free(restore);
- if (device)
- idevice_free(device);
-}
-
const char* restore_progress_string(unsigned int operation) {
switch (operation) {
case CREATE_PARTITION_MAP:
@@ -300,7 +337,7 @@ int restore_handle_progress_msg(restored_client_t client, plist_t msg) {
plist_get_uint_val(node, &progress);
if ((progress > 0) && (progress < 100)) {
- print_progress_bar(restore_progress_string(operation), (double) progress);
+ print_progress_bar((double) progress);
} else {
info("%s\n", restore_progress_string(operation));
@@ -361,16 +398,32 @@ int restore_send_filesystem(idevice_t device, const char* filesystem) {
return 0;
}
-int restore_send_kernelcache(restored_client_t client, char* kernel_data, int len) {
+int restore_send_kernelcache(restored_client_t client, const char* ipsw, plist_t tss) {
+ int size = 0;
+ char* data = NULL;
+ char* path = NULL;
+ plist_t blob = NULL;
+ plist_t dict = NULL;
+ restored_error_t restore_error = RESTORE_E_SUCCESS;
+
info("Sending kernelcache\n");
+ if (tss_get_entry_path(tss, "KernelCache", &path) < 0) {
+ error("ERROR: Unable to find kernelcache path\n");
+ return -1;
+ }
- plist_t kernelcache_node = plist_new_data(kernel_data, len);
+ if (get_signed_component(client, ipsw, tss, path, &data, &size) < 0) {
+ error("ERROR: Unable to get kernelcache file\n");
+ return -1;
+ }
- plist_t dict = plist_new_dict();
- plist_dict_insert_item(dict, "KernelCacheFile", kernelcache_node);
- restored_error_t ret = restored_send(client, dict);
- if (ret != RESTORE_E_SUCCESS) {
+ dict = plist_new_dict();
+ blob = plist_new_data(data, size);
+ plist_dict_insert_item(dict, "KernelCacheFile", blob);
+
+ restore_error = restored_send(client, dict);
+ if (restore_error != RESTORE_E_SUCCESS) {
error("ERROR: Unable to send kernelcache data\n");
plist_free(dict);
return -1;
@@ -378,52 +431,61 @@ int restore_send_kernelcache(restored_client_t client, char* kernel_data, int le
info("Done sending kernelcache\n");
plist_free(dict);
+ free(data);
return 0;
}
int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) {
char* llb_path = NULL;
+ char* llb_filename = NULL;
+ char firmware_path[256];
+ char manifest_file[256];
+ int manifest_size = 0;
+ char* manifest_data = NULL;
+ char firmware_filename[256];
+ int llb_size = 0;
+ char* llb_data = NULL;
+ plist_t dict = NULL;
+ char* filename = NULL;
+ int nor_size = 0;
+ char* nor_data = NULL;
+ plist_t norimage_array = NULL;
+ restored_error_t ret = RESTORE_E_SUCCESS;
+
if (tss_get_entry_path(tss, "LLB", &llb_path) < 0) {
error("ERROR: Unable to get LLB info from TSS response\n");
return -1;
}
- char* llb_filename = strstr(llb_path, "LLB");
+ llb_filename = strstr(llb_path, "LLB");
if (llb_filename == NULL) {
error("ERROR: Unable to extract firmware path from LLB filename\n");
free(llb_path);
return -1;
}
- char firmware_path[256];
memset(firmware_path, '\0', sizeof(firmware_path));
memcpy(firmware_path, llb_path, (llb_filename - 1) - llb_path);
info("Found firmware path %s\n", firmware_path);
- char manifest_file[256];
memset(manifest_file, '\0', sizeof(manifest_file));
snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path);
info("Getting firmware manifest %s\n", manifest_file);
- int manifest_size = 0;
- char* manifest_data = NULL;
if (ipsw_extract_to_memory(ipsw, manifest_file, &manifest_data, &manifest_size) < 0) {
error("ERROR: Unable to extract firmware manifest from ipsw\n");
free(llb_path);
return -1;
}
- char firmware_filename[256];
memset(firmware_filename, '\0', sizeof(firmware_filename));
- int llb_size = 0;
- char* llb_data = NULL;
- plist_t dict = plist_new_dict();
- char* filename = strtok(manifest_data, "\n");
+ dict = plist_new_dict();
+ filename = strtok(manifest_data, "\n");
if (filename != NULL) {
memset(firmware_filename, '\0', sizeof(firmware_filename));
snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename);
- if (get_signed_component(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) {
+ if (get_signed_component(client, ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) {
error("ERROR: Unable to get signed LLB\n");
return -1;
}
@@ -431,14 +493,12 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) {
plist_dict_insert_item(dict, "LlbImageData", plist_new_data(llb_data, (uint64_t) llb_size));
}
- int nor_size = 0;
- char* nor_data = NULL;
filename = strtok(NULL, "\n");
- plist_t norimage_array = plist_new_array();
+ norimage_array = plist_new_array();
while (filename != NULL) {
memset(firmware_filename, '\0', sizeof(firmware_filename));
snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename);
- if (get_signed_component(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) {
+ if (get_signed_component(client, ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) {
error("ERROR: Unable to get signed firmware %s\n", firmware_filename);
break;
}
@@ -453,7 +513,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) {
debug_plist(dict);
- restored_error_t ret = restored_send(client, dict);
+ ret = restored_send(client, dict);
if (ret != RESTORE_E_SUCCESS) {
error("ERROR: Unable to send kernelcache data\n");
plist_free(dict);
@@ -464,7 +524,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) {
return 0;
}
-int restore_handle_data_request_msg(idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem) {
+int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem) {
char* type = NULL;
plist_t node = NULL;
@@ -476,44 +536,39 @@ int restore_handle_data_request_msg(idevice_t device, restored_client_t restore,
// this request is sent when restored is ready to receive the filesystem
if (!strcmp(type, "SystemImageData")) {
- restore_send_filesystem(device, filesystem);
-
- }
-
- else if (!strcmp(type, "KernelCache")) {
- int kernelcache_size = 0;
- char* kernelcache_data = NULL;
- char* kernelcache_path = NULL;
- if (tss_get_entry_path(tss, "KernelCache", &kernelcache_path) < 0) {
- error("ERROR: Unable to find kernelcache path\n");
+ if(restore_send_filesystem(device, filesystem) < 0) {
+ error("ERROR: Unable to send filesystem\n");
return -1;
}
+ }
- if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) {
- error("ERROR: Unable to get kernelcache file\n");
+ else if (!strcmp(type, "KernelCache")) {
+ if(restore_send_kernelcache(restore, ipsw, tss) < 0) {
+ error("ERROR: Unable to send kernelcache\n");
return -1;
}
- restore_send_kernelcache(restore, kernelcache_data, kernelcache_size);
- free(kernelcache_data);
-
}
else if (!strcmp(type, "NORData")) {
- if(!idevicerestore_exclude) {
- restore_send_nor(restore, ipsw, tss);
+ if(client->flags & FLAG_EXCLUDE > 0) {
+ if(restore_send_nor(restore, ipsw, tss) < 0) {
+ error("ERROR: Unable to send NOR data\n");
+ return -1;
+ }
} else {
- idevicerestore_quit = 1;
+ client->flags &= 1;
}
} else {
// Unknown DataType!!
debug("Unknown data request received\n");
+ debug_plist(message);
}
}
return 0;
}
-int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) {
+int restore_device(struct idevicerestore_client_t* client, const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) {
int error = 0;
char* type = NULL;
char* kernel = NULL;
@@ -525,7 +580,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char*
restored_error_t restore_error = RESTORE_E_SUCCESS;
// open our connection to the device and verify we're in restore mode
- if (restore_open_with_timeout(uuid, &device, &restore) < 0) {
+ if (restore_open_with_timeout(client) < 0) {
error("ERROR: Unable to open device in restore mode\n");
return -1;
}
@@ -541,7 +596,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char*
// this is the restore process loop, it reads each message in from
// restored and passes that data on to it's specific handler
- while (!idevicerestore_quit) {
+ while ((client->flags & FLAG_QUIT) == 0) {
restore_error = restored_receive(restore, &message);
if (restore_error != RESTORE_E_SUCCESS) {
debug("No data to read\n");
@@ -564,7 +619,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char*
// files sent to the server by the client. these data requests include
// SystemImageData, KernelCache, and NORData requests
if (!strcmp(type, "DataRequestMsg")) {
- error = restore_handle_data_request_msg(device, restore, message, tss, ipsw, filesystem);
+ error = restore_handle_data_request_msg(client, device, restore, message, tss, ipsw, filesystem);
}
// progress notification messages sent by the restored inform the client
@@ -590,7 +645,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char*
// an unrecoverable error, so we need to bail.
if (error < 0) {
error("ERROR: Unable to successfully restore device\n");
- idevicerestore_quit = 1;
+ client->flags &= FLAG_QUIT;
}
plist_free(message);
diff --git a/src/restore.h b/src/restore.h
index cf9cf51..5446aa8 100644
--- a/src/restore.h
+++ b/src/restore.h
@@ -1,4 +1,4 @@
-/*
+ /*
* restore.h
* Functions for handling idevices in restore mode
*
@@ -22,21 +22,41 @@
#ifndef IDEVICERESTORE_RESTORE_H
#define IDEVICERESTORE_RESTORE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <plist/plist.h>
#include <libimobiledevice/restore.h>
#include <libimobiledevice/libimobiledevice.h>
-int restore_reboot(const char* uuid);
+struct restore_client_t {
+ plist_t tss;
+ idevice_t device;
+ const char* uuid;
+ unsigned int operation;
+ const char* filesystem;
+ restored_client_t client;
+};
+
int restore_check_mode(const char* uuid);
int restore_check_device(const char* uuid);
+int restore_client_new(struct idevicerestore_client_t* client);
+void restore_client_free(struct idevicerestore_client_t* client);
+int restore_reboot(struct idevicerestore_client_t* client);
const char* restore_progress_string(unsigned int operation);
-void restore_close(idevice_t device, restored_client_t restore);
int restore_handle_status_msg(restored_client_t client, plist_t msg);
int restore_handle_progress_msg(restored_client_t client, plist_t msg);
+int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem);
int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss);
-int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len);
-int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem);
-int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* client);
+int restore_send_kernelcache(restored_client_t client, const char* ipsw, plist_t tss);
+int restore_device(struct idevicerestore_client_t* client, const char* uuid, const char* ipsw, plist_t tss, const char* filesystem);
+int restore_open_with_timeout(struct idevicerestore_client_t* client);
int restore_send_filesystem(idevice_t device, const char* filesystem);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/src/tss.h b/src/tss.h
index ff60da0..d45c74c 100644
--- a/src/tss.h
+++ b/src/tss.h
@@ -22,6 +22,10 @@
#ifndef IDEVICERESTORE_TSS_H
#define IDEVICERESTORE_TSS_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <plist/plist.h>
plist_t tss_send_request(plist_t request);
@@ -30,4 +34,9 @@ int tss_get_entry_path(plist_t tss, const char* entry, char** path);
int tss_get_blob_by_path(plist_t tss, const char* path, char** blob);
int tss_get_blob_by_name(plist_t tss, const char* entry, char** blob);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif