summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--include/libimobiledevice/restore.h71
-rw-r--r--src/Makefile.am3
-rw-r--r--src/restore.c408
-rw-r--r--src/restore.h36
5 files changed, 518 insertions, 2 deletions
diff --git a/AUTHORS b/AUTHORS
index a8820b1..de03fac 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,8 +2,8 @@ Bastien Nocera
2Bryan Forbes 2Bryan Forbes
3Christophe Fergeau 3Christophe Fergeau
4Ingmar Vanhassel 4Ingmar Vanhassel
5JonathanBeck
6Jonathan Beck 5Jonathan Beck
6Joshua Hill
7Martin Aumueller 7Martin Aumueller
8Martin Szulecki 8Martin Szulecki
9Matt Colyer 9Matt Colyer
diff --git a/include/libimobiledevice/restore.h b/include/libimobiledevice/restore.h
new file mode 100644
index 0000000..c4b5916
--- /dev/null
+++ b/include/libimobiledevice/restore.h
@@ -0,0 +1,71 @@
1/**
2 * @file libimobiledevice/restore.h
3 * @brief Implementation to communicate with the restore device daemon
4 * \internal
5 *
6 * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#ifndef RESTORE_H
24#define RESTORE_H
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30#include <libimobiledevice/libimobiledevice.h>
31
32/** @name Error Codes */
33/*@{*/
34#define RESTORE_E_SUCCESS 0
35#define RESTORE_E_INVALID_ARG -1
36#define RESTORE_E_INVALID_CONF -2
37#define RESTORE_E_PLIST_ERROR -3
38#define RESTORE_E_DICT_ERROR -4
39#define RESTORE_E_NOT_ENOUGH_DATA -5
40#define RESTORE_E_MUX_ERROR -6
41#define RESTORE_E_START_RESTORE_FAILED -7
42
43#define RESTORE_E_UNKNOWN_ERROR -256
44/*@}*/
45
46/** Represents an error code. */
47typedef int16_t restored_error_t;
48
49typedef struct restored_client_private restored_client_private;
50typedef restored_client_private *restored_client_t; /**< The client handle. */
51
52/* Interface */
53restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label);
54restored_error_t restored_client_free(restored_client_t client);
55
56restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version);
57restored_error_t restored_send(restored_client_t client, plist_t plist);
58restored_error_t restored_receive(restored_client_t client, plist_t *plist);
59restored_error_t restored_goodbye(restored_client_t client);
60
61restored_error_t restored_start_restore(restored_client_t client);
62restored_error_t restored_reboot(restored_client_t client);
63
64/* Helper */
65void restored_client_set_label(restored_client_t client, const char *label);
66
67#ifdef __cplusplus
68}
69#endif
70
71#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 5fa37d7..338daf2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -19,4 +19,5 @@ libimobiledevice_la_SOURCES = idevice.c idevice.h \
19 mobile_image_mounter.c mobile_image_mounter.h\ 19 mobile_image_mounter.c mobile_image_mounter.h\
20 screenshotr.c screenshotr.h\ 20 screenshotr.c screenshotr.h\
21 mobilesync.c mobilesync.h\ 21 mobilesync.c mobilesync.h\
22 mobilebackup.c mobilebackup.h 22 mobilebackup.c mobilebackup.h\
23 restore.c restore.h
diff --git a/src/restore.c b/src/restore.c
new file mode 100644
index 0000000..8acefef
--- /dev/null
+++ b/src/restore.c
@@ -0,0 +1,408 @@
1/*
2 * restore.c
3 * com.apple.mobile.restored service implementation.
4 *
5 * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <arpa/inet.h>
23#include <errno.h>
24#include <string.h>
25#include <stdlib.h>
26#include <glib.h>
27#include <plist/plist.h>
28
29#include "property_list_service.h"
30#include "restore.h"
31#include "idevice.h"
32#include "debug.h"
33
34#define RESULT_SUCCESS 0
35#define RESULT_FAILURE 1
36
37/**
38 * Internally used function for checking the result from restore's answer
39 * plist to a previously sent request.
40 *
41 * @param dict The plist to evaluate.
42 * @param query_match Name of the request to match.
43 *
44 * @return RESULT_SUCCESS when the result is 'Success',
45 * RESULT_FAILURE when the result is 'Failure',
46 * or a negative value if an error occured during evaluation.
47 */
48static int restored_check_result(plist_t dict)
49{
50 int ret = -1;
51 plist_t result_node = plist_dict_get_item(dict, "Result");
52 if (!result_node) {
53 return ret;
54 }
55
56 plist_type result_type = plist_get_node_type(result_node);
57
58 if (result_type == PLIST_STRING) {
59
60 char *result_value = NULL;
61
62 plist_get_string_val(result_node, &result_value);
63
64 if (result_value) {
65 if (!strcmp(result_value, "Success")) {
66 ret = RESULT_SUCCESS;
67 } else if (!strcmp(result_value, "Failure")) {
68 ret = RESULT_FAILURE;
69 } else {
70 debug_info("ERROR: unknown result value '%s'", result_value);
71 }
72 }
73 if (result_value)
74 free(result_value);
75 }
76 return ret;
77}
78
79/**
80 * Adds a label key with the passed value to a plist dict node.
81 *
82 * @param plist The plist to add the key to
83 * @param label The value for the label key
84 *
85 */
86static void plist_dict_add_label(plist_t plist, const char *label)
87{
88 if (plist && label) {
89 if (plist_get_node_type(plist) == PLIST_DICT)
90 plist_dict_insert_item(plist, "Label", plist_new_string(label));
91 }
92}
93
94/**
95 * Closes the restored client session if one is running and frees up the
96 * restored_client struct.
97 *
98 * @param client The restore client
99 *
100 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
101 */
102restored_error_t restored_client_free(restored_client_t client)
103{
104 if (!client)
105 return RESTORE_E_INVALID_ARG;
106 restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
107
108 if (client->parent) {
109 restored_goodbye(client);
110
111 if (property_list_service_client_free(client->parent) == PROPERTY_LIST_SERVICE_E_SUCCESS) {
112 ret = RESTORE_E_SUCCESS;
113 }
114 }
115
116 if (client->uuid) {
117 free(client->uuid);
118 }
119 if (client->label) {
120 free(client->label);
121 }
122
123 free(client);
124 return ret;
125}
126
127/**
128 * Sets the label to send for requests to restored.
129 *
130 * @param client The restore client
131 * @param label The label to set or NULL to disable sending a label
132 *
133 */
134void restored_client_set_label(restored_client_t client, const char *label)
135{
136 if (client) {
137 if (client->label)
138 free(client->label);
139
140 client->label = (label != NULL) ? strdup(label): NULL;
141 }
142}
143
144/**
145 * Receives a plist from restored.
146 *
147 * @param client The restored client
148 * @param plist The plist to store the received data
149 *
150 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client or
151 * plist is NULL
152 */
153restored_error_t restored_receive(restored_client_t client, plist_t *plist)
154{
155 if (!client || !plist || (plist && *plist))
156 return RESTORE_E_INVALID_ARG;
157 restored_error_t ret = RESTORE_E_SUCCESS;
158 property_list_service_error_t err;
159
160 err = property_list_service_receive_plist(client->parent, plist);
161 if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
162 ret = RESTORE_E_UNKNOWN_ERROR;
163 }
164
165 if (!*plist)
166 ret = RESTORE_E_PLIST_ERROR;
167
168 return ret;
169}
170
171/**
172 * Sends a plist to restored.
173 *
174 * @note This function is low-level and should only be used if you need to send
175 * a new type of message.
176 *
177 * @param client The restored client
178 * @param plist The plist to send
179 *
180 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client or
181 * plist is NULL
182 */
183restored_error_t restored_send(restored_client_t client, plist_t plist)
184{
185 if (!client || !plist)
186 return RESTORE_E_INVALID_ARG;
187
188 restored_error_t ret = RESTORE_E_SUCCESS;
189 idevice_error_t err;
190
191 err = property_list_service_send_xml_plist(client->parent, plist);
192 if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
193 ret = RESTORE_E_UNKNOWN_ERROR;
194 }
195 return ret;
196}
197
198/**
199 * Query the type of the service daemon. Depending on whether the device is
200 * queried in normal mode or restore mode, different types will be returned.
201 *
202 * @param client The restored client
203 * @param type The type returned by the service daemon. Pass NULL to ignore.
204 * @param version The restore protocol version. Pass NULL to ignore.
205 *
206 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
207 */
208restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version)
209{
210 if (!client)
211 return RESTORE_E_INVALID_ARG;
212
213 restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
214
215 plist_t dict = plist_new_dict();
216 plist_dict_add_label(dict, client->label);
217 plist_dict_insert_item(dict,"Request", plist_new_string("QueryType"));
218
219 debug_info("called");
220 ret = restored_send(client, dict);
221
222 plist_free(dict);
223 dict = NULL;
224
225 ret = restored_receive(client, &dict);
226
227 if (RESTORE_E_SUCCESS != ret)
228 return ret;
229
230 ret = RESTORE_E_UNKNOWN_ERROR;
231 if (restored_check_result(dict) == RESULT_SUCCESS) {
232 /* return the type if requested */
233 if (type != NULL) {
234 plist_t type_node = plist_dict_get_item(dict, "Type");
235 plist_get_string_val(type_node, type);
236 }
237 debug_info("success with type %s", *type);
238 ret = RESTORE_E_SUCCESS;
239
240 /* fetch the restore protocol version */
241 plist_t version_node = plist_dict_get_item(dict, "RestoreProtocolVersion");
242 if (version_node && version) {
243 plist_get_uint_val(version_node, version);
244 debug_info("restored protocol version %llu", *version);
245 ret = RESTORE_E_SUCCESS;
246 } else
247 ret = RESTORE_E_UNKNOWN_ERROR;
248
249 }
250 plist_free(dict);
251 dict = NULL;
252
253 return ret;
254}
255
256/**
257 * Creates a new restored client for the device.
258 *
259 * @param device The device to create a restored client for
260 * @param client The pointer to the location of the new restored_client
261 * @param label The label to use for communication. Usually the program name.
262 *
263 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
264 */
265restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label)
266{
267 if (!client)
268 return RESTORE_E_INVALID_ARG;
269
270 restored_error_t ret = RESTORE_E_SUCCESS;
271
272 property_list_service_client_t plistclient = NULL;
273 if (property_list_service_client_new(device, 0xf27e, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
274 debug_info("could not connect to restored (device %s)", device->uuid);
275 return RESTORE_E_MUX_ERROR;
276 }
277
278 restored_client_t client_loc = (restored_client_t) malloc(sizeof(struct restored_client_private));
279 client_loc->parent = plistclient;
280 client_loc->uuid = NULL;
281 client_loc->label = NULL;
282 if (label != NULL)
283 client_loc->label = strdup(label);
284
285 ret = idevice_get_uuid(device, &client_loc->uuid);
286 if (RESTORE_E_SUCCESS != ret) {
287 debug_info("failed to get device uuid.");
288 }
289 debug_info("device uuid: %s", client_loc->uuid);
290
291 if (RESTORE_E_SUCCESS == ret) {
292 *client = client_loc;
293 } else {
294 restored_client_free(client_loc);
295 }
296
297 return ret;
298}
299
300/**
301 * Sends the Goodbye request to restored signaling the end of communication.
302 *
303 * @param client The restore client
304 *
305 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL,
306 * RESTORE_E_PLIST_ERROR if the device did not acknowledge the request
307 */
308restored_error_t restored_goodbye(restored_client_t client)
309{
310 if (!client)
311 return RESTORE_E_INVALID_ARG;
312
313 restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
314
315 plist_t dict = plist_new_dict();
316 plist_dict_add_label(dict, client->label);
317 plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye"));
318
319 debug_info("called");
320
321 ret = restored_send(client, dict);
322 plist_free(dict);
323 dict = NULL;
324
325 ret = restored_receive(client, &dict);
326 if (!dict) {
327 debug_info("did not get goodbye response back");
328 return RESTORE_E_PLIST_ERROR;
329 }
330
331 if (restored_check_result(dict) == RESULT_SUCCESS) {
332 debug_info("success");
333 ret = RESTORE_E_SUCCESS;
334 }
335 plist_free(dict);
336 dict = NULL;
337 return ret;
338}
339
340/**
341 * Requests to start a restore and retrieve it's port on success.
342 *
343 * @param client The restored client
344 *
345 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter
346 * is NULL, RESTORE_E_START_RESTORE_FAILED if the request fails
347 */
348restored_error_t restored_start_restore(restored_client_t client)
349{
350 if (!client)
351 return RESTORE_E_INVALID_ARG;
352
353 plist_t dict = NULL;
354 restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
355
356 dict = plist_new_dict();
357 plist_dict_add_label(dict, client->label);
358 plist_dict_insert_item(dict,"Request", plist_new_string("StartRestore"));
359 plist_dict_insert_item(dict,"RestoreProtocolVersion", plist_new_uint(2));
360
361 /* send to device */
362 ret = restored_send(client, dict);
363 plist_free(dict);
364 dict = NULL;
365
366 return ret;
367}
368
369/**
370 * Requests device to reboot.
371 *
372 * @param client The restored client
373 *
374 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter
375 * is NULL
376 */
377restored_error_t restored_reboot(restored_client_t client)
378{
379 if (!client)
380 return RESTORE_E_INVALID_ARG;
381
382 plist_t dict = NULL;
383 restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
384
385 dict = plist_new_dict();
386 plist_dict_add_label(dict, client->label);
387 plist_dict_insert_item(dict,"Request", plist_new_string("Reboot"));
388
389 /* send to device */
390 ret = restored_send(client, dict);
391 plist_free(dict);
392 dict = NULL;
393
394 if (RESTORE_E_SUCCESS != ret)
395 return ret;
396
397 ret = restored_receive(client, &dict);
398 if (RESTORE_E_SUCCESS != ret)
399 return ret;
400
401 if (!dict)
402 return RESTORE_E_PLIST_ERROR;
403
404 plist_free(dict);
405 dict = NULL;
406 return ret;
407}
408
diff --git a/src/restore.h b/src/restore.h
new file mode 100644
index 0000000..8b4cbbb
--- /dev/null
+++ b/src/restore.h
@@ -0,0 +1,36 @@
1/*
2 * restore.h
3 * Defines restore stuff, like the client struct.
4 *
5 * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef RESTORED_H
23#define RESTORED_H
24
25#include <string.h>
26
27#include "libimobiledevice/restore.h"
28#include "property_list_service.h"
29
30struct restored_client_private {
31 property_list_service_client_t parent;
32 char *uuid;
33 char *label;
34};
35
36#endif