summaryrefslogtreecommitdiffstats
path: root/src/idevicerestore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/idevicerestore.c')
-rw-r--r--src/idevicerestore.c324
1 files changed, 220 insertions, 104 deletions
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index 059ae08..02c1bc1 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -153,108 +153,23 @@ static int load_version_data(struct idevicerestore_client_t* client)
return 0;
}
-int main(int argc, char* argv[]) {
- int opt = 0;
- int optindex = 0;
- char* ipsw = NULL;
- char* udid = NULL;
+int idevicerestore_start(struct idevicerestore_client_t* client)
+{
int tss_enabled = 0;
int result = 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");
+ if (!client) {
return -1;
}
- memset(client, '\0', sizeof(struct idevicerestore_client_t));
- while ((opt = getopt_long(argc, argv, "dhcesxtpli:u:nC:", longopts, &optindex)) > 0) {
- switch (opt) {
- case 'h':
- usage(argc, argv);
- return 0;
-
- case 'd':
- client->flags |= FLAG_DEBUG;
- idevicerestore_debug = 1;
- break;
-
- case 'e':
- client->flags |= FLAG_ERASE;
- break;
-
- case 'c':
- client->flags |= FLAG_CUSTOM;
- break;
-
- case 's':
- client->tss_url = strdup("http://cydia.saurik.com/TSS/controller?action=2");
- break;
-
- case 'x':
- client->flags |= FLAG_EXCLUDE;
- break;
-
- case 'l':
- client->flags |= FLAG_LATEST;
- break;
-
- case 'i':
- if (optarg) {
- char* tail = NULL;
- client->ecid = strtoull(optarg, &tail, 16);
- if (tail && (tail[0] != '\0')) {
- client->ecid = 0;
- }
- if (client->ecid == 0) {
- error("ERROR: Could not parse ECID from '%s'\n", optarg);
- return -1;
- }
- }
- break;
-
- case 'u':
- udid = optarg;
- break;
-
- case 't':
- client->flags |= FLAG_SHSHONLY;
- break;
-
- case 'p':
- client->flags |= FLAG_PWN;
- break;
-
- case 'n':
- client->flags |= FLAG_NOACTION;
- break;
-
- case 'C':
- client->cache_dir = strdup(optarg);
- break;
-
- default:
- usage(argc, argv);
- return -1;
- }
- }
-
- if (((argc-optind) == 1) || (client->flags & FLAG_PWN) || (client->flags & FLAG_LATEST)) {
- argc -= optind;
- argv += optind;
-
- ipsw = argv[0];
- } else {
- usage(argc, argv);
+ if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) {
+ error("ERROR: FLAG_LATEST cannot be used with FLAG_CUSTOM.\n");
return -1;
}
- if (client->flags & FLAG_LATEST) {
- if (client->flags & FLAG_CUSTOM) {
- error("ERROR: You can't use --custom and --latest options at the same time.\n");
- return -1;
- }
+ if (!client->ipsw && !(client->flags & FLAG_PWN) && !(client->flags & FLAG_LATEST)) {
+ error("ERROR: no ipsw file given\n");
+ return -1;
}
if (client->flags & FLAG_DEBUG) {
@@ -262,9 +177,6 @@ int main(int argc, char* argv[]) {
irecv_set_debug_level(1);
}
- client->udid = udid;
- client->ipsw = ipsw;
-
// update version data (from cache, or apple if too old)
load_version_data(client);
@@ -374,8 +286,12 @@ int main(int argc, char* argv[]) {
}
if (client->flags & FLAG_LATEST) {
+ char* ipsw = NULL;
int res = ipsw_download_latest_fw(client->version_data, client->device->product, "cache", &ipsw);
if (res != 0) {
+ if (ipsw) {
+ free(ipsw);
+ }
return res;
} else {
client->ipsw = ipsw;
@@ -398,8 +314,8 @@ int main(int argc, char* argv[]) {
}
// verify if ipsw file exists
- if (access(ipsw, F_OK) < 0) {
- error("ERROR: Firmware file %s does not exist.\n", ipsw);
+ if (access(client->ipsw, F_OK) < 0) {
+ error("ERROR: Firmware file %s does not exist.\n", client->ipsw);
return -1;
}
@@ -407,14 +323,14 @@ int main(int argc, char* argv[]) {
plist_t buildmanifest = NULL;
if (client->flags & FLAG_CUSTOM) {
info("Extracting Restore.plist from IPSW\n");
- if (ipsw_extract_restore_plist(ipsw, &buildmanifest) < 0) {
- error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", ipsw);
+ if (ipsw_extract_restore_plist(client->ipsw, &buildmanifest) < 0) {
+ error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw);
return -1;
}
} else {
info("Extracting BuildManifest from IPSW\n");
- if (ipsw_extract_build_manifest(ipsw, &buildmanifest, &tss_enabled) < 0) {
- error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", ipsw);
+ if (ipsw_extract_build_manifest(client->ipsw, &buildmanifest, &tss_enabled) < 0) {
+ error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw);
return -1;
}
}
@@ -473,7 +389,7 @@ int main(int argc, char* argv[]) {
char *files[16];
char *fmanifest = NULL;
uint32_t msize = 0;
- if (ipsw_extract_to_memory(ipsw, tmpstr, &fmanifest, &msize) < 0) {
+ if (ipsw_extract_to_memory(client->ipsw, tmpstr, &fmanifest, &msize) < 0) {
error("ERROR: could not extract %s from IPSW\n", tmpstr);
return -1;
}
@@ -707,7 +623,7 @@ int main(int argc, char* argv[]) {
strcat(tmpf, basename(ipswtmp));
free(ipswtmp);
} else {
- strcpy(tmpf, ipsw);
+ strcpy(tmpf, client->ipsw);
}
char* p = strrchr((const char*)tmpf, '.');
if (p) {
@@ -918,6 +834,206 @@ int main(int argc, char* argv[]) {
return result;
}
+struct idevicerestore_client_t* idevicerestore_client_new()
+{
+ 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 NULL;
+ }
+ memset(client, '\0', sizeof(struct idevicerestore_client_t));
+ return client;
+}
+
+void idevicerestore_client_free(struct idevicerestore_client_t* client)
+{
+ if (!client) {
+ return;
+ }
+
+ if (client->tss_url) {
+ free(client->tss_url);
+ }
+ if (client->version_data) {
+ plist_free(client->version_data);
+ }
+ if (client->nonce) {
+ free(client->nonce);
+ }
+ if (client->udid) {
+ free(client->udid);
+ }
+ if (client->srnm) {
+ free(client->srnm);
+ }
+ if (client->ipsw) {
+ free(client->ipsw);
+ }
+ if (client->version) {
+ free(client->version);
+ }
+ if (client->build) {
+ free(client->build);
+ }
+ if (client->restore_boot_args) {
+ free(client->restore_boot_args);
+ }
+ if (client->cache_dir) {
+ free(client->cache_dir);
+ }
+ free(client);
+}
+
+void idevicerestore_set_ecid(struct idevicerestore_client_t* client, unsigned long long ecid)
+{
+ if (!client)
+ return;
+ client->ecid = ecid;
+}
+
+void idevicerestore_set_udid(struct idevicerestore_client_t* client, const char* udid)
+{
+ if (!client)
+ return;
+ if (client->udid) {
+ free(client->udid);
+ client->udid = NULL;
+ }
+ if (udid) {
+ client->udid = strdup(udid);
+ }
+}
+
+void idevicerestore_set_flags(struct idevicerestore_client_t* client, int flags)
+{
+ if (!client)
+ return;
+ client->flags = flags;
+}
+
+void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char* path)
+{
+ if (!client)
+ return;
+ if (client->ipsw) {
+ free(client->ipsw);
+ client->ipsw = NULL;
+ }
+ if (path) {
+ client->ipsw = strdup(path);
+ }
+}
+
+#ifndef IDEVICERESTORE_NOMAIN
+int main(int argc, char* argv[]) {
+ int opt = 0;
+ int optindex = 0;
+ char* ipsw = NULL;
+ char* udid = NULL;
+ int result = 0;
+
+ struct idevicerestore_client_t* client = idevicerestore_client_new();
+ if (client == NULL) {
+ error("ERROR: could not create idevicerestore client\n");
+ return -1;
+ }
+
+ while ((opt = getopt_long(argc, argv, "dhcesxtpli:u:nC:", longopts, &optindex)) > 0) {
+ switch (opt) {
+ case 'h':
+ usage(argc, argv);
+ return 0;
+
+ case 'd':
+ client->flags |= FLAG_DEBUG;
+ idevicerestore_debug = 1;
+ break;
+
+ case 'e':
+ client->flags |= FLAG_ERASE;
+ break;
+
+ case 'c':
+ client->flags |= FLAG_CUSTOM;
+ break;
+
+ case 's':
+ client->tss_url = strdup("http://cydia.saurik.com/TSS/controller?action=2");
+ break;
+
+ case 'x':
+ client->flags |= FLAG_EXCLUDE;
+ break;
+
+ case 'l':
+ client->flags |= FLAG_LATEST;
+ break;
+
+ case 'i':
+ if (optarg) {
+ char* tail = NULL;
+ client->ecid = strtoull(optarg, &tail, 16);
+ if (tail && (tail[0] != '\0')) {
+ client->ecid = 0;
+ }
+ if (client->ecid == 0) {
+ error("ERROR: Could not parse ECID from '%s'\n", optarg);
+ return -1;
+ }
+ }
+ break;
+
+ case 'u':
+ client->udid = strdup(optarg);
+ break;
+
+ case 't':
+ client->flags |= FLAG_SHSHONLY;
+ break;
+
+ case 'p':
+ client->flags |= FLAG_PWN;
+ break;
+
+ case 'n':
+ client->flags |= FLAG_NOACTION;
+ break;
+
+ case 'C':
+ client->cache_dir = strdup(optarg);
+ break;
+
+ default:
+ usage(argc, argv);
+ return -1;
+ }
+ }
+
+ if (((argc-optind) == 1) || (client->flags & FLAG_PWN) || (client->flags & FLAG_LATEST)) {
+ argc -= optind;
+ argv += optind;
+
+ ipsw = argv[0];
+ } else {
+ usage(argc, argv);
+ return -1;
+ }
+
+ if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) {
+ error("ERROR: You can't use --custom and --latest options at the same time.\n");
+ return -1;
+ }
+
+ client->ipsw = strdup(ipsw);
+
+ result = idevicerestore_start(client);
+
+ idevicerestore_client_free(client);
+
+ return result;
+}
+#endif
+
int check_mode(struct idevicerestore_client_t* client) {
int mode = MODE_UNKNOWN;
int dfumode = MODE_UNKNOWN;