~ubuntu-branches/ubuntu/wily/libimobiledevice/wily

« back to all changes in this revision

Viewing changes to src/restore.c

  • Committer: Package Import Robot
  • Author(s): Julien Lavergne
  • Date: 2011-09-16 00:01:44 UTC
  • mfrom: (1.1.8 upstream) (6.1.6 experimental)
  • Revision ID: package-import@ubuntu.com-20110916000144-13otcnnzl0rapoly
Tags: 1.1.1-2
* Upload to unstable, most of the API should be stable now.
* debian/patches/
 - 02-add-missing-linking.patch: Refresh
 - 03_ac_pkg_swig_m4_fixed.patch: Fix building python bindings. Thanks
   Sebastian Ramacher for the patch (Closes: #631821).
 - 04_libplist_DSO_linking.patch: Add libplist to LDFLAGS.
* debian/control:
 - Build-depends on dh-autoreconf for 03_ac_pkg_swig_m4_fixed.patch.
 - Add DM-Upload-Allowed: yes
* debian/rules:
 - Run dh --with autoreconf for 03_ac_pkg_swig_m4_fixed.patch.
 - Remove .la files for python bindings also.
 - Remove .a files from python bindings.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
48
static 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
 */
 
86
static 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
 */
 
102
restored_error_t restored_client_free(restored_client_t client)
 
103
{
 
104
        if (!client)
 
105
                return RESTORE_E_INVALID_ARG;
 
106
                
 
107
        restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
 
108
 
 
109
        if (client->parent) {
 
110
                restored_goodbye(client);
 
111
 
 
112
                if (property_list_service_client_free(client->parent) == PROPERTY_LIST_SERVICE_E_SUCCESS) {
 
113
                        ret = RESTORE_E_SUCCESS;
 
114
                }
 
115
        }
 
116
 
 
117
        if (client->uuid) {
 
118
                free(client->uuid);
 
119
        }
 
120
        if (client->label) {
 
121
                free(client->label);
 
122
        }
 
123
        
 
124
        if (client->info) {
 
125
                plist_free(client->info);
 
126
        }
 
127
 
 
128
        free(client);
 
129
        return ret;
 
130
}
 
131
 
 
132
/**
 
133
 * Sets the label to send for requests to restored.
 
134
 *
 
135
 * @param client The restore client
 
136
 * @param label The label to set or NULL to disable sending a label
 
137
 *
 
138
 */
 
139
void restored_client_set_label(restored_client_t client, const char *label)
 
140
{
 
141
        if (client) {
 
142
                if (client->label)
 
143
                        free(client->label);
 
144
 
 
145
                client->label = (label != NULL) ? strdup(label): NULL;
 
146
        }
 
147
}
 
148
 
 
149
/**
 
150
 * Receives a plist from restored.
 
151
 *
 
152
 * @param client The restored client
 
153
 * @param plist The plist to store the received data
 
154
 *
 
155
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client or
 
156
 *  plist is NULL
 
157
 */
 
158
restored_error_t restored_receive(restored_client_t client, plist_t *plist)
 
159
{
 
160
        if (!client || !plist || (plist && *plist))
 
161
                return RESTORE_E_INVALID_ARG;
 
162
                
 
163
        restored_error_t ret = RESTORE_E_SUCCESS;
 
164
        property_list_service_error_t err;
 
165
 
 
166
        err = property_list_service_receive_plist(client->parent, plist);
 
167
        if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
 
168
                ret = RESTORE_E_UNKNOWN_ERROR;
 
169
        }
 
170
 
 
171
        if (!*plist)
 
172
                ret = RESTORE_E_PLIST_ERROR;
 
173
 
 
174
        return ret;
 
175
}
 
176
 
 
177
/**
 
178
 * Sends a plist to restored.
 
179
 *
 
180
 * @note This function is low-level and should only be used if you need to send
 
181
 *        a new type of message.
 
182
 *
 
183
 * @param client The restored client
 
184
 * @param plist The plist to send
 
185
 *
 
186
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client or
 
187
 *  plist is NULL
 
188
 */
 
189
restored_error_t restored_send(restored_client_t client, plist_t plist)
 
190
{
 
191
        if (!client || !plist)
 
192
                return RESTORE_E_INVALID_ARG;
 
193
 
 
194
        restored_error_t ret = RESTORE_E_SUCCESS;
 
195
        idevice_error_t err;
 
196
 
 
197
        err = property_list_service_send_xml_plist(client->parent, plist);
 
198
        if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
 
199
                ret = RESTORE_E_UNKNOWN_ERROR;
 
200
        }
 
201
        return ret;
 
202
}
 
203
 
 
204
/**
 
205
 * Query the type of the service daemon. Depending on whether the device is
 
206
 * queried in normal mode or restore mode, different types will be returned.
 
207
 *
 
208
 * @param client The restored client
 
209
 * @param type The type returned by the service daemon. Pass NULL to ignore.
 
210
 * @param version The restore protocol version. Pass NULL to ignore.
 
211
 *
 
212
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
 
213
 */
 
214
restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version)
 
215
{
 
216
        if (!client)
 
217
                return RESTORE_E_INVALID_ARG;
 
218
 
 
219
        restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
 
220
 
 
221
        plist_t dict = plist_new_dict();
 
222
        plist_dict_add_label(dict, client->label);
 
223
        plist_dict_insert_item(dict,"Request", plist_new_string("QueryType"));
 
224
 
 
225
        debug_info("called");
 
226
        ret = restored_send(client, dict);
 
227
 
 
228
        plist_free(dict);
 
229
        dict = NULL;
 
230
 
 
231
        ret = restored_receive(client, &dict);
 
232
        
 
233
        if (RESTORE_E_SUCCESS != ret)
 
234
                return ret;
 
235
 
 
236
        ret = RESTORE_E_UNKNOWN_ERROR;
 
237
        if (restored_check_result(dict) == RESULT_SUCCESS) {
 
238
                /* save our device information info */
 
239
                client->info = dict;
 
240
                
 
241
                /* return the type if requested */
 
242
                if (type) {
 
243
                        plist_t type_node = plist_dict_get_item(dict, "Type");
 
244
                        if (type_node && PLIST_STRING == plist_get_node_type(type_node)) {
 
245
                                plist_get_string_val(type_node, type);
 
246
                                debug_info("success with type %s", *type);
 
247
                                ret = RESTORE_E_SUCCESS;
 
248
                        } else {
 
249
                                return RESTORE_E_UNKNOWN_ERROR;
 
250
                        }
 
251
                }
 
252
 
 
253
                /* fetch the restore protocol version */
 
254
                if (version) {
 
255
                        plist_t version_node = plist_dict_get_item(dict, "RestoreProtocolVersion");
 
256
                        if (version_node && PLIST_UINT == plist_get_node_type(version_node)) {
 
257
                                plist_get_uint_val(version_node, version);
 
258
                                debug_info("restored protocol version %llu", *version);
 
259
                                ret = RESTORE_E_SUCCESS;
 
260
                        } else {
 
261
                                return RESTORE_E_UNKNOWN_ERROR;
 
262
                        }
 
263
                }
 
264
                ret = RESTORE_E_SUCCESS;
 
265
        }
 
266
 
 
267
        return ret;
 
268
}
 
269
 
 
270
/**
 
271
 * Retrieves a value from information plist specified by a key.
 
272
 *
 
273
 * @param client An initialized restored client.
 
274
 * @param key The key name to request or NULL to query for all keys
 
275
 * @param value A plist node representing the result value node
 
276
 *
 
277
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL, RESTORE_E_PLIST_ERROR if value for key can't be found
 
278
 */
 
279
restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value) 
 
280
{
 
281
        if (!client || !value || (value && *value))
 
282
                return RESTORE_E_INVALID_ARG;
 
283
                
 
284
        if (!client->info)
 
285
                return RESTORE_E_NOT_ENOUGH_DATA;
 
286
                
 
287
        restored_error_t ret = RESTORE_E_SUCCESS;
 
288
        plist_t item = NULL;
 
289
        
 
290
        if (!key) {
 
291
                *value = plist_copy(client->info);
 
292
                return RESTORE_E_SUCCESS;
 
293
        } else {
 
294
                item = plist_dict_get_item(client->info, key);
 
295
        }
 
296
        
 
297
        if (item) {
 
298
                *value = plist_copy(item);
 
299
        } else {
 
300
                ret = RESTORE_E_PLIST_ERROR;
 
301
        }
 
302
        
 
303
        return ret;
 
304
}
 
305
 
 
306
/**
 
307
 * Creates a new restored client for the device.
 
308
 *
 
309
 * @param device The device to create a restored client for
 
310
 * @param client The pointer to the location of the new restored_client
 
311
 * @param label The label to use for communication. Usually the program name.
 
312
 *
 
313
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
 
314
 */
 
315
restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label)
 
316
{
 
317
        if (!client)
 
318
                return RESTORE_E_INVALID_ARG;
 
319
 
 
320
        restored_error_t ret = RESTORE_E_SUCCESS;
 
321
 
 
322
        property_list_service_client_t plistclient = NULL;
 
323
        if (property_list_service_client_new(device, 0xf27e, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
 
324
                debug_info("could not connect to restored (device %s)", device->uuid);
 
325
                return RESTORE_E_MUX_ERROR;
 
326
        }
 
327
 
 
328
        restored_client_t client_loc = (restored_client_t) malloc(sizeof(struct restored_client_private));
 
329
        client_loc->parent = plistclient;
 
330
        client_loc->uuid = NULL;
 
331
        client_loc->label = NULL;
 
332
        if (label != NULL)
 
333
                client_loc->label = strdup(label);
 
334
 
 
335
        ret = idevice_get_uuid(device, &client_loc->uuid);
 
336
        if (RESTORE_E_SUCCESS != ret) {
 
337
                debug_info("failed to get device uuid.");
 
338
        }
 
339
        debug_info("device uuid: %s", client_loc->uuid);
 
340
 
 
341
        if (RESTORE_E_SUCCESS == ret) {
 
342
                *client = client_loc;
 
343
        } else {
 
344
                restored_client_free(client_loc);
 
345
        }
 
346
 
 
347
        return ret;
 
348
}
 
349
 
 
350
/**
 
351
 * Sends the Goodbye request to restored signaling the end of communication.
 
352
 *
 
353
 * @param client The restore client
 
354
 *
 
355
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL,
 
356
 *  RESTORE_E_PLIST_ERROR if the device did not acknowledge the request
 
357
 */
 
358
restored_error_t restored_goodbye(restored_client_t client)
 
359
{
 
360
        if (!client)
 
361
                return RESTORE_E_INVALID_ARG;
 
362
 
 
363
        restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
 
364
 
 
365
        plist_t dict = plist_new_dict();
 
366
        plist_dict_add_label(dict, client->label);
 
367
        plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye"));
 
368
 
 
369
        debug_info("called");
 
370
 
 
371
        ret = restored_send(client, dict);
 
372
        plist_free(dict);
 
373
        dict = NULL;
 
374
 
 
375
        ret = restored_receive(client, &dict);
 
376
        if (!dict) {
 
377
                debug_info("did not get goodbye response back");
 
378
                return RESTORE_E_PLIST_ERROR;
 
379
        }
 
380
 
 
381
        if (restored_check_result(dict) == RESULT_SUCCESS) {
 
382
                debug_info("success");
 
383
                ret = RESTORE_E_SUCCESS;
 
384
        }
 
385
        plist_free(dict);
 
386
        dict = NULL;
 
387
        return ret;
 
388
}
 
389
 
 
390
/**
 
391
 * Requests to start a restore and retrieve it's port on success.
 
392
 *
 
393
 * @param client The restored client
 
394
 *
 
395
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter
 
396
 *  is NULL, RESTORE_E_START_RESTORE_FAILED if the request fails
 
397
 */
 
398
restored_error_t restored_start_restore(restored_client_t client)
 
399
{
 
400
        if (!client)
 
401
                return RESTORE_E_INVALID_ARG;
 
402
 
 
403
        plist_t dict = NULL;
 
404
        restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
 
405
 
 
406
        dict = plist_new_dict();
 
407
        plist_dict_add_label(dict, client->label);
 
408
        plist_dict_insert_item(dict,"Request", plist_new_string("StartRestore"));
 
409
        plist_dict_insert_item(dict,"RestoreProtocolVersion", plist_new_uint(2));
 
410
 
 
411
        /* send to device */
 
412
        ret = restored_send(client, dict);
 
413
        plist_free(dict);
 
414
        dict = NULL;
 
415
 
 
416
        return ret;
 
417
}
 
418
 
 
419
/**
 
420
 * Requests device to reboot.
 
421
 *
 
422
 * @param client The restored client
 
423
 *
 
424
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter
 
425
 *  is NULL
 
426
 */
 
427
restored_error_t restored_reboot(restored_client_t client)
 
428
{
 
429
        if (!client)
 
430
                return RESTORE_E_INVALID_ARG;
 
431
 
 
432
        plist_t dict = NULL;
 
433
        restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
 
434
 
 
435
        dict = plist_new_dict();
 
436
        plist_dict_add_label(dict, client->label);
 
437
        plist_dict_insert_item(dict,"Request", plist_new_string("Reboot"));
 
438
 
 
439
        /* send to device */
 
440
        ret = restored_send(client, dict);
 
441
        plist_free(dict);
 
442
        dict = NULL;
 
443
 
 
444
        if (RESTORE_E_SUCCESS != ret)
 
445
                return ret;
 
446
 
 
447
        ret = restored_receive(client, &dict);
 
448
        if (RESTORE_E_SUCCESS != ret)
 
449
                return ret;
 
450
 
 
451
        if (!dict)
 
452
                return RESTORE_E_PLIST_ERROR;
 
453
 
 
454
        plist_free(dict);
 
455
        dict = NULL;
 
456
        return ret;
 
457
}
 
458