diff options
| author | 2012-11-29 16:46:30 +0100 | |
|---|---|---|
| committer | 2012-11-29 16:46:30 +0100 | |
| commit | ed47413660eb3f49e55b795513990269491ad0c7 (patch) | |
| tree | 8711e4b8dd292e6b4934eaee95d84122766f44ba | |
| parent | 14bacd927e8621d723a3d67c49f43a0485c3eff4 (diff) | |
| download | libimobiledevice-ed47413660eb3f49e55b795513990269491ad0c7.tar.gz libimobiledevice-ed47413660eb3f49e55b795513990269491ad0c7.tar.bz2 | |
idevicebackup2: add --source option to allow using backup directories from other devices
| -rw-r--r-- | tools/idevicebackup2.c | 115 |
1 files changed, 39 insertions, 76 deletions
diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c index 0a06f3f..7256ee9 100644 --- a/tools/idevicebackup2.c +++ b/tools/idevicebackup2.c | |||
| @@ -472,67 +472,6 @@ static int mb2_status_check_snapshot_state(const char *path, const char *udid, c | |||
| 472 | return ret; | 472 | return ret; |
| 473 | } | 473 | } |
| 474 | 474 | ||
| 475 | static int mobilebackup_info_is_current_device(plist_t info) | ||
| 476 | { | ||
| 477 | plist_t value_node = NULL; | ||
| 478 | plist_t node = NULL; | ||
| 479 | plist_t root_node = NULL; | ||
| 480 | int ret = 0; | ||
| 481 | |||
| 482 | if (!info) | ||
| 483 | return ret; | ||
| 484 | |||
| 485 | if (plist_get_node_type(info) != PLIST_DICT) | ||
| 486 | return ret; | ||
| 487 | |||
| 488 | /* get basic device information in one go */ | ||
| 489 | lockdownd_get_value(client, NULL, NULL, &root_node); | ||
| 490 | |||
| 491 | /* verify UDID */ | ||
| 492 | value_node = plist_dict_get_item(root_node, "UniqueDeviceID"); | ||
| 493 | node = plist_dict_get_item(info, "Target Identifier"); | ||
| 494 | |||
| 495 | if(plist_compare_node_value(value_node, node)) | ||
| 496 | ret = 1; | ||
| 497 | else { | ||
| 498 | printf("Info.plist: UniqueDeviceID does not match.\n"); | ||
| 499 | } | ||
| 500 | |||
| 501 | /* verify SerialNumber */ | ||
| 502 | if (ret == 1) { | ||
| 503 | value_node = plist_dict_get_item(root_node, "SerialNumber"); | ||
| 504 | node = plist_dict_get_item(info, "Serial Number"); | ||
| 505 | |||
| 506 | if(plist_compare_node_value(value_node, node)) | ||
| 507 | ret = 1; | ||
| 508 | else { | ||
| 509 | printf("Info.plist: SerialNumber does not match.\n"); | ||
| 510 | ret = 0; | ||
| 511 | } | ||
| 512 | } | ||
| 513 | |||
| 514 | /* verify ProductVersion to prevent using backup with different OS version */ | ||
| 515 | if (ret == 1) { | ||
| 516 | value_node = plist_dict_get_item(root_node, "ProductVersion"); | ||
| 517 | node = plist_dict_get_item(info, "Product Version"); | ||
| 518 | |||
| 519 | if(plist_compare_node_value(value_node, node)) | ||
| 520 | ret = 1; | ||
| 521 | else { | ||
| 522 | printf("Info.plist: ProductVersion does not match.\n"); | ||
| 523 | ret = 0; | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 527 | plist_free(root_node); | ||
| 528 | root_node = NULL; | ||
| 529 | |||
| 530 | value_node = NULL; | ||
| 531 | node = NULL; | ||
| 532 | |||
| 533 | return ret; | ||
| 534 | } | ||
| 535 | |||
| 536 | static void do_post_notification(const char *notification) | 475 | static void do_post_notification(const char *notification) |
| 537 | { | 476 | { |
| 538 | uint16_t nport = 0; | 477 | uint16_t nport = 0; |
| @@ -1186,6 +1125,7 @@ static void print_usage(int argc, char **argv) | |||
| 1186 | printf("options:\n"); | 1125 | printf("options:\n"); |
| 1187 | printf(" -d, --debug\t\tenable communication debugging\n"); | 1126 | printf(" -d, --debug\t\tenable communication debugging\n"); |
| 1188 | printf(" -u, --udid UDID\ttarget specific device by its 40-digit device UDID\n"); | 1127 | printf(" -u, --udid UDID\ttarget specific device by its 40-digit device UDID\n"); |
| 1128 | printf(" -s, --source UDID\tuse backup data from device specified by UDID\n"); | ||
| 1189 | printf(" -h, --help\t\tprints usage information\n"); | 1129 | printf(" -h, --help\t\tprints usage information\n"); |
| 1190 | printf("\n"); | 1130 | printf("\n"); |
| 1191 | } | 1131 | } |
| @@ -1195,6 +1135,7 @@ int main(int argc, char *argv[]) | |||
| 1195 | idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; | 1135 | idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; |
| 1196 | int i; | 1136 | int i; |
| 1197 | char* udid = NULL; | 1137 | char* udid = NULL; |
| 1138 | char* source_udid = NULL; | ||
| 1198 | uint16_t port = 0; | 1139 | uint16_t port = 0; |
| 1199 | int cmd = -1; | 1140 | int cmd = -1; |
| 1200 | int cmd_flags = 0; | 1141 | int cmd_flags = 0; |
| @@ -1229,6 +1170,15 @@ int main(int argc, char *argv[]) | |||
| 1229 | udid = strdup(argv[i]); | 1170 | udid = strdup(argv[i]); |
| 1230 | continue; | 1171 | continue; |
| 1231 | } | 1172 | } |
| 1173 | else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--source")) { | ||
| 1174 | i++; | ||
| 1175 | if (!argv[i] || (strlen(argv[i]) != 40)) { | ||
| 1176 | print_usage(argc, argv); | ||
| 1177 | return 0; | ||
| 1178 | } | ||
| 1179 | source_udid = strdup(argv[i]); | ||
| 1180 | continue; | ||
| 1181 | } | ||
| 1232 | else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { | 1182 | else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { |
| 1233 | print_usage(argc, argv); | 1183 | print_usage(argc, argv); |
| 1234 | return 0; | 1184 | return 0; |
| @@ -1307,12 +1257,16 @@ int main(int argc, char *argv[]) | |||
| 1307 | idevice_get_udid(device, &udid); | 1257 | idevice_get_udid(device, &udid); |
| 1308 | } | 1258 | } |
| 1309 | 1259 | ||
| 1260 | if (!source_udid) { | ||
| 1261 | source_udid = strdup(udid); | ||
| 1262 | } | ||
| 1263 | |||
| 1310 | /* backup directory must contain an Info.plist */ | 1264 | /* backup directory must contain an Info.plist */ |
| 1311 | char *info_path = build_path(backup_directory, udid, "Info.plist", NULL); | 1265 | char *info_path = build_path(backup_directory, source_udid, "Info.plist", NULL); |
| 1312 | if (cmd == CMD_RESTORE) { | 1266 | if (cmd == CMD_RESTORE) { |
| 1313 | if (stat(info_path, &st) != 0) { | 1267 | if (stat(info_path, &st) != 0) { |
| 1314 | free(info_path); | 1268 | free(info_path); |
| 1315 | printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found for UDID %s.\n", backup_directory, udid); | 1269 | printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found for UDID %s.\n", backup_directory, source_udid); |
| 1316 | return -1; | 1270 | return -1; |
| 1317 | } | 1271 | } |
| 1318 | } | 1272 | } |
| @@ -1387,12 +1341,6 @@ int main(int argc, char *argv[]) | |||
| 1387 | printf("Could not read Info.plist\n"); | 1341 | printf("Could not read Info.plist\n"); |
| 1388 | is_full_backup = 1; | 1342 | is_full_backup = 1; |
| 1389 | } | 1343 | } |
| 1390 | if (info_plist && ((cmd == CMD_BACKUP) || (cmd == CMD_RESTORE))) { | ||
| 1391 | if (!mobilebackup_info_is_current_device(info_plist)) { | ||
| 1392 | printf("Aborting. Backup data is not compatible with the current device.\n"); | ||
| 1393 | cmd = CMD_LEAVE; | ||
| 1394 | } | ||
| 1395 | } | ||
| 1396 | } else { | 1344 | } else { |
| 1397 | if (cmd == CMD_RESTORE) { | 1345 | if (cmd == CMD_RESTORE) { |
| 1398 | printf("Aborting restore. Info.plist is missing.\n"); | 1346 | printf("Aborting restore. Info.plist is missing.\n"); |
| @@ -1440,10 +1388,22 @@ checkpoint: | |||
| 1440 | PRINT_VERBOSE(1, "Starting backup...\n"); | 1388 | PRINT_VERBOSE(1, "Starting backup...\n"); |
| 1441 | 1389 | ||
| 1442 | /* make sure backup device sub-directory exists */ | 1390 | /* make sure backup device sub-directory exists */ |
| 1443 | char *devbackupdir = build_path(backup_directory, udid, NULL); | 1391 | char* devbackupdir = build_path(backup_directory, source_udid, NULL); |
| 1444 | __mkdir(devbackupdir, 0755); | 1392 | __mkdir(devbackupdir, 0755); |
| 1445 | free(devbackupdir); | 1393 | free(devbackupdir); |
| 1446 | 1394 | ||
| 1395 | if (strcmp(source_udid, udid) != 0) { | ||
| 1396 | /* handle different source backup directory */ | ||
| 1397 | // make sure target backup device sub-directory exists | ||
| 1398 | devbackupdir = build_path(backup_directory, udid, NULL); | ||
| 1399 | __mkdir(devbackupdir, 0755); | ||
| 1400 | free(devbackupdir); | ||
| 1401 | |||
| 1402 | // use Info.plist path in target backup folder */ | ||
| 1403 | free(info_path); | ||
| 1404 | info_path = build_path(backup_directory, udid, "Info.plist", NULL); | ||
| 1405 | } | ||
| 1406 | |||
| 1447 | /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */ | 1407 | /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */ |
| 1448 | /* TODO: verify battery on AC enough battery remaining */ | 1408 | /* TODO: verify battery on AC enough battery remaining */ |
| 1449 | 1409 | ||
| @@ -1463,7 +1423,7 @@ checkpoint: | |||
| 1463 | /* request backup from device with manifest from last backup */ | 1423 | /* request backup from device with manifest from last backup */ |
| 1464 | PRINT_VERBOSE(1, "Requesting backup from device...\n"); | 1424 | PRINT_VERBOSE(1, "Requesting backup from device...\n"); |
| 1465 | 1425 | ||
| 1466 | err = mobilebackup2_send_request(mobilebackup2, "Backup", udid, NULL, NULL); | 1426 | err = mobilebackup2_send_request(mobilebackup2, "Backup", udid, source_udid, NULL); |
| 1467 | if (err == MOBILEBACKUP2_E_SUCCESS) { | 1427 | if (err == MOBILEBACKUP2_E_SUCCESS) { |
| 1468 | if (is_full_backup) { | 1428 | if (is_full_backup) { |
| 1469 | PRINT_VERBOSE(1, "Full backup mode.\n"); | 1429 | PRINT_VERBOSE(1, "Full backup mode.\n"); |
| @@ -1485,7 +1445,7 @@ checkpoint: | |||
| 1485 | /* TODO: verify battery on AC enough battery remaining */ | 1445 | /* TODO: verify battery on AC enough battery remaining */ |
| 1486 | 1446 | ||
| 1487 | /* verify if Status.plist says we read from an successful backup */ | 1447 | /* verify if Status.plist says we read from an successful backup */ |
| 1488 | if (!mb2_status_check_snapshot_state(backup_directory, udid, "finished")) { | 1448 | if (!mb2_status_check_snapshot_state(backup_directory, source_udid, "finished")) { |
| 1489 | printf("ERROR: Cannot ensure we restore from a successful backup. Aborting.\n"); | 1449 | printf("ERROR: Cannot ensure we restore from a successful backup. Aborting.\n"); |
| 1490 | cmd = CMD_LEAVE; | 1450 | cmd = CMD_LEAVE; |
| 1491 | break; | 1451 | break; |
| @@ -1505,7 +1465,7 @@ checkpoint: | |||
| 1505 | plist_dict_insert_item(opts, "RestorePreserveSettings", plist_new_bool((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0)); | 1465 | plist_dict_insert_item(opts, "RestorePreserveSettings", plist_new_bool((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0)); |
| 1506 | PRINT_VERBOSE(1, "Preserve settings of device: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0 ? "Yes":"No")); | 1466 | PRINT_VERBOSE(1, "Preserve settings of device: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0 ? "Yes":"No")); |
| 1507 | 1467 | ||
| 1508 | err = mobilebackup2_send_request(mobilebackup2, "Restore", udid, udid, opts); | 1468 | err = mobilebackup2_send_request(mobilebackup2, "Restore", udid, source_udid, opts); |
| 1509 | plist_free(opts); | 1469 | plist_free(opts); |
| 1510 | if (err != MOBILEBACKUP2_E_SUCCESS) { | 1470 | if (err != MOBILEBACKUP2_E_SUCCESS) { |
| 1511 | if (err == MOBILEBACKUP2_E_BAD_VERSION) { | 1471 | if (err == MOBILEBACKUP2_E_BAD_VERSION) { |
| @@ -1520,7 +1480,7 @@ checkpoint: | |||
| 1520 | break; | 1480 | break; |
| 1521 | case CMD_INFO: | 1481 | case CMD_INFO: |
| 1522 | PRINT_VERBOSE(1, "Requesting backup info from device...\n"); | 1482 | PRINT_VERBOSE(1, "Requesting backup info from device...\n"); |
| 1523 | err = mobilebackup2_send_request(mobilebackup2, "Info", udid, NULL, NULL); | 1483 | err = mobilebackup2_send_request(mobilebackup2, "Info", udid, source_udid, NULL); |
| 1524 | if (err != MOBILEBACKUP2_E_SUCCESS) { | 1484 | if (err != MOBILEBACKUP2_E_SUCCESS) { |
| 1525 | printf("Error requesting backup info from device, error code %d\n", err); | 1485 | printf("Error requesting backup info from device, error code %d\n", err); |
| 1526 | cmd = CMD_LEAVE; | 1486 | cmd = CMD_LEAVE; |
| @@ -1528,7 +1488,7 @@ checkpoint: | |||
| 1528 | break; | 1488 | break; |
| 1529 | case CMD_LIST: | 1489 | case CMD_LIST: |
| 1530 | PRINT_VERBOSE(1, "Requesting backup list from device...\n"); | 1490 | PRINT_VERBOSE(1, "Requesting backup list from device...\n"); |
| 1531 | err = mobilebackup2_send_request(mobilebackup2, "List", udid, NULL, NULL); | 1491 | err = mobilebackup2_send_request(mobilebackup2, "List", udid, source_udid, NULL); |
| 1532 | if (err != MOBILEBACKUP2_E_SUCCESS) { | 1492 | if (err != MOBILEBACKUP2_E_SUCCESS) { |
| 1533 | printf("Error requesting backup list from device, error code %d\n", err); | 1493 | printf("Error requesting backup list from device, error code %d\n", err); |
| 1534 | cmd = CMD_LEAVE; | 1494 | cmd = CMD_LEAVE; |
| @@ -1536,7 +1496,7 @@ checkpoint: | |||
| 1536 | break; | 1496 | break; |
| 1537 | case CMD_UNBACK: | 1497 | case CMD_UNBACK: |
| 1538 | PRINT_VERBOSE(1, "Starting to unpack backup...\n"); | 1498 | PRINT_VERBOSE(1, "Starting to unpack backup...\n"); |
| 1539 | err = mobilebackup2_send_request(mobilebackup2, "Unback", udid, NULL, NULL); | 1499 | err = mobilebackup2_send_request(mobilebackup2, "Unback", udid, source_udid, NULL); |
| 1540 | if (err != MOBILEBACKUP2_E_SUCCESS) { | 1500 | if (err != MOBILEBACKUP2_E_SUCCESS) { |
| 1541 | printf("Error requesting unback operation from device, error code %d\n", err); | 1501 | printf("Error requesting unback operation from device, error code %d\n", err); |
| 1542 | cmd = CMD_LEAVE; | 1502 | cmd = CMD_LEAVE; |
| @@ -1889,6 +1849,9 @@ files_out: | |||
| 1889 | if (udid) { | 1849 | if (udid) { |
| 1890 | free(udid); | 1850 | free(udid); |
| 1891 | } | 1851 | } |
| 1852 | if (source_udid) { | ||
| 1853 | free(source_udid); | ||
| 1854 | } | ||
| 1892 | 1855 | ||
| 1893 | return 0; | 1856 | return 0; |
| 1894 | } | 1857 | } |
