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 | } |