diff options
Diffstat (limited to 'tools/idevicebackup.c')
| -rw-r--r-- | tools/idevicebackup.c | 152 |
1 files changed, 83 insertions, 69 deletions
diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c index 1e512d8..0affd7a 100644 --- a/tools/idevicebackup.c +++ b/tools/idevicebackup.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <errno.h> | 31 | #include <errno.h> |
| 32 | #include <stdlib.h> | 32 | #include <stdlib.h> |
| 33 | #include <signal.h> | 33 | #include <signal.h> |
| 34 | #include <getopt.h> | ||
| 34 | #if defined(HAVE_OPENSSL) | 35 | #if defined(HAVE_OPENSSL) |
| 35 | #include <openssl/sha.h> | 36 | #include <openssl/sha.h> |
| 36 | #elif defined(HAVE_GNUTLS) | 37 | #elif defined(HAVE_GNUTLS) |
| @@ -647,27 +648,28 @@ static void clean_exit(int sig) | |||
| 647 | quit_flag++; | 648 | quit_flag++; |
| 648 | } | 649 | } |
| 649 | 650 | ||
| 650 | static void print_usage(int argc, char **argv) | 651 | static void print_usage(int argc, char **argv, int is_error) |
| 651 | { | 652 | { |
| 652 | char *name = NULL; | 653 | char *name = strrchr(argv[0], '/'); |
| 653 | name = strrchr(argv[0], '/'); | 654 | fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] CMD DIRECTORY\n", (name ? name + 1: argv[0])); |
| 654 | printf("Usage: %s [OPTIONS] CMD [DIRECTORY]\n", (name ? name + 1: argv[0])); | 655 | fprintf(is_error ? stderr : stdout, |
| 655 | printf("\n"); | 656 | "\n" |
| 656 | printf("Create or restore backup from the current or specified directory.\n"); | 657 | "Create or restore backup in/from the specified directory.\n" |
| 657 | printf("\n"); | 658 | "\n" |
| 658 | printf("CMD:\n"); | 659 | "CMD:\n" |
| 659 | printf(" backup\tSaves a device backup into DIRECTORY\n"); | 660 | " backup Saves a device backup into DIRECTORY\n" |
| 660 | printf(" restore\tRestores a device backup from DIRECTORY.\n"); | 661 | " restore Restores a device backup from DIRECTORY.\n" |
| 661 | printf("\n"); | 662 | "\n" |
| 662 | printf("OPTIONS:\n"); | 663 | "OPTIONS:\n" |
| 663 | printf(" -u, --udid UDID\ttarget specific device by UDID\n"); | 664 | " -u, --udid UDID target specific device by UDID\n" |
| 664 | printf(" -n, --network\t\tconnect to network device\n"); | 665 | " -n, --network connect to network device\n" |
| 665 | printf(" -d, --debug\t\tenable communication debugging\n"); | 666 | " -d, --debug enable communication debugging\n" |
| 666 | printf(" -h, --help\t\tprints usage information\n"); | 667 | " -h, --help prints usage information\n" |
| 667 | printf(" -v, --version\t\tprints version information\n"); | 668 | " -v, --version prints version information\n" |
| 668 | printf("\n"); | 669 | "\n" |
| 669 | printf("Homepage: <" PACKAGE_URL ">\n"); | 670 | "Homepage: <" PACKAGE_URL ">\n" |
| 670 | printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n"); | 671 | "Bug Reports: <" PACKAGE_BUGREPORT ">\n" |
| 672 | ); | ||
| 671 | } | 673 | } |
| 672 | 674 | ||
| 673 | int main(int argc, char *argv[]) | 675 | int main(int argc, char *argv[]) |
| @@ -691,7 +693,15 @@ int main(int argc, char *argv[]) | |||
| 691 | uint64_t length = 0; | 693 | uint64_t length = 0; |
| 692 | uint64_t backup_total_size = 0; | 694 | uint64_t backup_total_size = 0; |
| 693 | enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE; | 695 | enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE; |
| 694 | uint64_t c = 0; | 696 | int c = 0; |
| 697 | const struct option longopts[] = { | ||
| 698 | { "debug", no_argument, NULL, 'd' }, | ||
| 699 | { "help", no_argument, NULL, 'h' }, | ||
| 700 | { "udid", required_argument, NULL, 'u' }, | ||
| 701 | { "network", no_argument, NULL, 'n' }, | ||
| 702 | { "version", no_argument, NULL, 'v' }, | ||
| 703 | { NULL, 0, NULL, 0} | ||
| 704 | }; | ||
| 695 | 705 | ||
| 696 | /* we need to exit cleanly on running backups and restores or we cause havok */ | 706 | /* we need to exit cleanly on running backups and restores or we cause havok */ |
| 697 | signal(SIGINT, clean_exit); | 707 | signal(SIGINT, clean_exit); |
| @@ -702,59 +712,58 @@ int main(int argc, char *argv[]) | |||
| 702 | #endif | 712 | #endif |
| 703 | 713 | ||
| 704 | /* parse cmdline args */ | 714 | /* parse cmdline args */ |
| 705 | for (i = 1; i < argc; i++) { | 715 | while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) { |
| 706 | if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { | 716 | switch (c) { |
| 717 | case 'd': | ||
| 707 | idevice_set_debug_level(1); | 718 | idevice_set_debug_level(1); |
| 708 | continue; | 719 | break; |
| 709 | } | 720 | case 'u': |
| 710 | else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) { | 721 | if (!*optarg) { |
| 711 | i++; | 722 | fprintf(stderr, "ERROR: UDID must not be empty!\n"); |
| 712 | if (!argv[i] || !*argv[i]) { | 723 | print_usage(argc, argv, 1); |
| 713 | print_usage(argc, argv); | 724 | return 2; |
| 714 | return 0; | ||
| 715 | } | 725 | } |
| 716 | udid = strdup(argv[i]); | 726 | udid = strdup(optarg); |
| 717 | continue; | 727 | break; |
| 718 | } | 728 | case 'n': |
| 719 | else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) { | ||
| 720 | use_network = 1; | 729 | use_network = 1; |
| 721 | continue; | 730 | break; |
| 722 | } | 731 | case 'h': |
| 723 | else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { | 732 | print_usage(argc, argv, 0); |
| 724 | print_usage(argc, argv); | ||
| 725 | return 0; | 733 | return 0; |
| 726 | } | 734 | case 'v': |
| 727 | else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { | ||
| 728 | printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); | 735 | printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); |
| 729 | return 0; | 736 | return 0; |
| 730 | } | 737 | default: |
| 731 | else if (!strcmp(argv[i], "backup")) { | 738 | print_usage(argc, argv, 1); |
| 732 | cmd = CMD_BACKUP; | 739 | return 2; |
| 733 | } | ||
| 734 | else if (!strcmp(argv[i], "restore")) { | ||
| 735 | cmd = CMD_RESTORE; | ||
| 736 | } | ||
| 737 | else if (backup_directory == NULL) { | ||
| 738 | backup_directory = argv[i]; | ||
| 739 | } | ||
| 740 | else { | ||
| 741 | print_usage(argc, argv); | ||
| 742 | return 0; | ||
| 743 | } | 740 | } |
| 744 | } | 741 | } |
| 742 | argc -= optind; | ||
| 743 | argv += optind; | ||
| 745 | 744 | ||
| 746 | /* verify options */ | 745 | if (argc < 1) { |
| 747 | if (cmd == -1) { | 746 | fprintf(stderr, "ERROR: Missing command.\n"); |
| 748 | printf("No command specified.\n"); | 747 | print_usage(argc+optind, argv-optind, 1); |
| 749 | print_usage(argc, argv); | 748 | return 2; |
| 750 | return -1; | ||
| 751 | } | 749 | } |
| 752 | 750 | ||
| 753 | if (backup_directory == NULL) { | 751 | if (!strcmp(argv[0], "backup")) { |
| 754 | printf("No target backup directory specified.\n"); | 752 | cmd = CMD_BACKUP; |
| 755 | print_usage(argc, argv); | 753 | } else if (!strcmp(argv[0], "restore")) { |
| 756 | return -1; | 754 | cmd = CMD_RESTORE; |
| 755 | } else { | ||
| 756 | fprintf(stderr, "ERROR: Invalid command '%s'.\n", argv[0]); | ||
| 757 | print_usage(argc+optind, argv-optind, 1); | ||
| 758 | return 2; | ||
| 759 | } | ||
| 760 | |||
| 761 | if (argc < 2) { | ||
| 762 | fprintf(stderr, "No target backup directory specified.\n"); | ||
| 763 | print_usage(argc+optind, argv-optind, 1); | ||
| 764 | return 2; | ||
| 757 | } | 765 | } |
| 766 | backup_directory = argv[1]; | ||
| 758 | 767 | ||
| 759 | /* verify if passed backup directory exists */ | 768 | /* verify if passed backup directory exists */ |
| 760 | if (stat(backup_directory, &st) != 0) { | 769 | if (stat(backup_directory, &st) != 0) { |
| @@ -784,9 +793,14 @@ int main(int argc, char *argv[]) | |||
| 784 | return -1; | 793 | return -1; |
| 785 | } | 794 | } |
| 786 | 795 | ||
| 796 | if (!udid) { | ||
| 797 | idevice_get_udid(device, &udid); | ||
| 798 | } | ||
| 799 | |||
| 787 | if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) { | 800 | if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) { |
| 788 | printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret); | 801 | printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret); |
| 789 | idevice_free(device); | 802 | idevice_free(device); |
| 803 | free(udid); | ||
| 790 | return -1; | 804 | return -1; |
| 791 | } | 805 | } |
| 792 | 806 | ||
| @@ -806,6 +820,7 @@ int main(int argc, char *argv[]) | |||
| 806 | printf("ERROR: This tool is only compatible with iOS 3 or below. For newer iOS versions please use the idevicebackup2 tool.\n"); | 820 | printf("ERROR: This tool is only compatible with iOS 3 or below. For newer iOS versions please use the idevicebackup2 tool.\n"); |
| 807 | lockdownd_client_free(client); | 821 | lockdownd_client_free(client); |
| 808 | idevice_free(device); | 822 | idevice_free(device); |
| 823 | free(udid); | ||
| 809 | return -1; | 824 | return -1; |
| 810 | } | 825 | } |
| 811 | } | 826 | } |
| @@ -851,7 +866,7 @@ int main(int argc, char *argv[]) | |||
| 851 | ldret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &service); | 866 | ldret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &service); |
| 852 | if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) { | 867 | if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) { |
| 853 | printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, service->port); | 868 | printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, service->port); |
| 854 | mobilebackup_client_new(device, service, &mobilebackup); | 869 | printf("%d\n", mobilebackup_client_new(device, service, &mobilebackup)); |
| 855 | 870 | ||
| 856 | if (service) { | 871 | if (service) { |
| 857 | lockdownd_service_descriptor_free(service); | 872 | lockdownd_service_descriptor_free(service); |
| @@ -993,7 +1008,7 @@ int main(int argc, char *argv[]) | |||
| 993 | } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) { | 1008 | } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) { |
| 994 | printf("ERROR: Could not start backup process: device refused to start the backup process.\n"); | 1009 | printf("ERROR: Could not start backup process: device refused to start the backup process.\n"); |
| 995 | } else { | 1010 | } else { |
| 996 | printf("ERROR: Could not start backup process: unspecified error occurred\n"); | 1011 | printf("ERROR: Could not start backup process: unspecified error occurred (%d)\n", err); |
| 997 | } | 1012 | } |
| 998 | break; | 1013 | break; |
| 999 | } | 1014 | } |
| @@ -1015,6 +1030,7 @@ int main(int argc, char *argv[]) | |||
| 1015 | char *format_size = NULL; | 1030 | char *format_size = NULL; |
| 1016 | int is_manifest = 0; | 1031 | int is_manifest = 0; |
| 1017 | uint8_t b = 0; | 1032 | uint8_t b = 0; |
| 1033 | uint64_t u64val = 0; | ||
| 1018 | 1034 | ||
| 1019 | /* process series of DLSendFile messages */ | 1035 | /* process series of DLSendFile messages */ |
| 1020 | do { | 1036 | do { |
| @@ -1046,8 +1062,8 @@ int main(int argc, char *argv[]) | |||
| 1046 | 1062 | ||
| 1047 | /* check DLFileStatusKey (codes: 1 = Hunk, 2 = Last Hunk) */ | 1063 | /* check DLFileStatusKey (codes: 1 = Hunk, 2 = Last Hunk) */ |
| 1048 | node = plist_dict_get_item(node_tmp, "DLFileStatusKey"); | 1064 | node = plist_dict_get_item(node_tmp, "DLFileStatusKey"); |
| 1049 | plist_get_uint_val(node, &c); | 1065 | plist_get_uint_val(node, &u64val); |
| 1050 | file_status = c; | 1066 | file_status = u64val; |
| 1051 | 1067 | ||
| 1052 | /* get source filename */ | 1068 | /* get source filename */ |
| 1053 | node = plist_dict_get_item(node_tmp, "BackupManifestKey"); | 1069 | node = plist_dict_get_item(node_tmp, "BackupManifestKey"); |
| @@ -1610,9 +1626,7 @@ files_out: | |||
| 1610 | 1626 | ||
| 1611 | idevice_free(device); | 1627 | idevice_free(device); |
| 1612 | 1628 | ||
| 1613 | if (udid) { | 1629 | free(udid); |
| 1614 | free(udid); | ||
| 1615 | } | ||
| 1616 | 1630 | ||
| 1617 | return 0; | 1631 | return 0; |
| 1618 | } | 1632 | } |
