diff options
Diffstat (limited to 'tools/idevicebackup2.c')
-rw-r--r-- | tools/idevicebackup2.c | 661 |
1 files changed, 411 insertions, 250 deletions
diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c index 58fda8d..c73b269 100644 --- a/tools/idevicebackup2.c +++ b/tools/idevicebackup2.c @@ -2,8 +2,8 @@ * idevicebackup2.c * Command line interface to use the device's backup and restore service * - * Copyright (c) 2010-2018 Nikias Bassen All Rights Reserved. - * Copyright (c) 2009-2010 Martin Szulecki All Rights Reserved. + * Copyright (c) 2010-2022 Nikias Bassen, All Rights Reserved. + * Copyright (c) 2009-2010 Martin Szulecki, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,8 @@ #include <config.h> #endif +#define TOOL_NAME "idevicebackup2" + #include <stdio.h> #include <string.h> #include <errno.h> @@ -34,6 +36,7 @@ #include <libgen.h> #include <ctype.h> #include <time.h> +#include <getopt.h> #include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice/lockdown.h> @@ -42,7 +45,9 @@ #include <libimobiledevice/afc.h> #include <libimobiledevice/installation_proxy.h> #include <libimobiledevice/sbservices.h> -#include "common/utils.h" +#include <libimobiledevice/diagnostics_relay.h> +#include <libimobiledevice-glue/utils.h> +#include <plist/plist.h> #include <endianness.h> @@ -53,6 +58,9 @@ #include <windows.h> #include <conio.h> #define sleep(x) Sleep(x*1000) +#ifndef ELOOP +#define ELOOP 114 +#endif #else #include <termios.h> #include <sys/statvfs.h> @@ -177,9 +185,8 @@ static int mkdir_with_parents(const char *dir, int mode) if (!dir) return -1; if (__mkdir(dir, mode) == 0) { return 0; - } else { - if (errno == EEXIST) return 0; } + if (errno == EEXIST) return 0; int res; char *parent = strdup(dir); char *parentdir = dirname(parent); @@ -345,7 +352,7 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t d char *udid_uppercase = NULL; lockdownd_client_t lockdown = NULL; - if (lockdownd_client_new_with_handshake(device, &lockdown, "idevicebackup2") != LOCKDOWN_E_SUCCESS) { + if (lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME) != LOCKDOWN_E_SUCCESS) { return NULL; } @@ -366,7 +373,7 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t d plist_t app_dict = plist_new_dict(); plist_t installed_apps = plist_new_array(); instproxy_client_t ip = NULL; - if (instproxy_client_start_service(device, &ip, "idevicebackup2") == INSTPROXY_E_SUCCESS) { + if (instproxy_client_start_service(device, &ip, TOOL_NAME) == INSTPROXY_E_SUCCESS) { plist_t client_opts = instproxy_client_options_new(); instproxy_client_options_add(client_opts, "ApplicationType", "User", NULL); instproxy_client_options_set_return_attributes(client_opts, "CFBundleIdentifier", "ApplicationSINF", "iTunesMetadata", NULL); @@ -375,7 +382,7 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t d instproxy_browse(ip, client_opts, &apps); sbservices_client_t sbs = NULL; - if (sbservices_client_start_service(device, &sbs, "idevicebackup2") != SBSERVICES_E_SUCCESS) { + if (sbservices_client_start_service(device, &sbs, TOOL_NAME) != SBSERVICES_E_SUCCESS) { printf("Couldn't establish sbservices connection. Continuing anyway.\n"); } @@ -545,9 +552,11 @@ static int write_restore_applications(plist_t info_plist, afc_client_t afc) uint32_t applications_plist_xml_length = 0; plist_t applications_plist = plist_dict_get_item(info_plist, "Applications"); - if (applications_plist) { - plist_to_xml(applications_plist, &applications_plist_xml, &applications_plist_xml_length); + if (!applications_plist) { + printf("No Applications in Info.plist, skipping creation of RestoreApplications.plist\n"); + return 0; } + plist_to_xml(applications_plist, &applications_plist_xml, &applications_plist_xml_length); if (!applications_plist_xml) { printf("Error preparing RestoreApplications.plist\n"); goto leave; @@ -598,7 +607,7 @@ static int mb2_status_check_snapshot_state(const char *path, const char *udid, c plist_t status_plist = NULL; char *file_path = string_build_path(path, udid, "Status.plist", NULL); - plist_read_from_filename(&status_plist, file_path); + plist_read_from_file(file_path, &status_plist, NULL); free(file_path); if (!status_plist) { printf("Could not read Status.plist!\n"); @@ -626,19 +635,19 @@ static void do_post_notification(idevice_t device, const char *notification) lockdownd_client_t lockdown = NULL; - if (lockdownd_client_new_with_handshake(device, &lockdown, "idevicebackup2") != LOCKDOWN_E_SUCCESS) { + if (lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME) != LOCKDOWN_E_SUCCESS) { return; } - lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service); - if (service && service->port) { + lockdownd_error_t ldret = lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service); + if (ldret == LOCKDOWN_E_SUCCESS) { np_client_new(device, service, &np); if (np) { np_post_notification(np, notification); np_client_free(np); } } else { - printf("Could not start %s\n", NP_SERVICE_NAME); + printf("ERROR: Could not start service %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret)); } if (service) { @@ -737,8 +746,18 @@ static int errno_to_device_error(int errno_value) return -6; case EEXIST: return -7; + case ENOTDIR: + return -8; + case EISDIR: + return -9; + case ELOOP: + return -10; + case EIO: + return -11; + case ENOSPC: + return -15; default: - return -errno_value; + return -1; } } @@ -954,10 +973,12 @@ static int mb2_receive_filename(mobilebackup2_client_t mobilebackup2, char** fil if ((nlen == 0) && (rlen == 4)) { // a zero length means no more files to receive return 0; - } else if(rlen == 0) { + } + if (rlen == 0) { // device needs more time, waiting... continue; - } else if (nlen > 4096) { + } + if (nlen > 4096) { // filename length is too large printf("ERROR: %s: too large filename length (%d)!\n", __func__, nlen); return 0; @@ -1349,7 +1370,8 @@ static void get_hidden_input(char *buf, int maxlen) while ((c = my_getch())) { if ((c == '\r') || (c == '\n')) { break; - } else if (isprint(c)) { + } + if (isprint(c)) { if (pwlen < maxlen-1) buf[pwlen++] = c; fputc('*', stderr); @@ -1397,49 +1419,60 @@ static void clean_exit(int sig) quit_flag++; } -static void print_usage(int argc, char **argv) +static void print_usage(int argc, char **argv, int is_error) { - char *name = NULL; - name = strrchr(argv[0], '/'); - printf("Usage: %s [OPTIONS] CMD [CMDOPTIONS] DIRECTORY\n", (name ? name + 1: argv[0])); - printf("Create or restore backup from the current or specified directory.\n\n"); - printf("commands:\n"); - printf(" backup\tcreate backup for the device\n"); - printf(" --full\t\tforce full backup from device.\n"); - printf(" restore\trestore last backup to the device\n"); - printf(" --system\t\trestore system files, too.\n"); - printf(" --no-reboot\t\tdo NOT reboot the system when done (default: yes).\n"); - printf(" --copy\t\tcreate a copy of backup folder before restoring.\n"); - printf(" --settings\t\trestore device settings from the backup.\n"); - printf(" --remove\t\tremove items which are not being restored\n"); - printf(" --skip-apps\t\tdo not trigger re-installation of apps after restore\n"); - printf(" --password PWD\tsupply the password of the source backup\n"); - printf(" info\t\tshow details about last completed backup of device\n"); - printf(" list\t\tlist files of last completed backup in CSV format\n"); - printf(" unback\tunpack a completed backup in DIRECTORY/_unback_/\n"); - printf(" encryption on|off [PWD]\tenable or disable backup encryption\n"); - printf(" NOTE: password will be requested in interactive mode if omitted\n"); - printf(" changepw [OLD NEW] change backup password on target device\n"); - printf(" NOTE: passwords will be requested in interactive mode if omitted\n"); - printf(" cloud on|off\tenable or disable cloud use (requires iCloud account)\n"); - printf("\n"); - printf("options:\n"); - printf(" -d, --debug\t\tenable communication debugging\n"); - printf(" -u, --udid UDID\ttarget specific device by UDID\n"); - printf(" -s, --source UDID\tuse backup data from device specified by UDID\n"); - printf(" -i, --interactive\trequest passwords interactively\n"); - printf(" -h, --help\t\tprints usage information\n"); - printf("\n"); - printf("Homepage: <" PACKAGE_URL ">\n"); + char *name = strrchr(argv[0], '/'); + fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] CMD [CMDOPTIONS] DIRECTORY\n", (name ? name + 1: argv[0])); + fprintf(is_error ? stderr : stdout, + "\n" + "Create or restore backup in/from the specified directory.\n" + "\n" + "CMD:\n" + " backup create backup for the device\n" + " --full force full backup from device.\n" + " restore restore last backup to the device\n" + " --system restore system files, too.\n" + " --no-reboot do NOT reboot the device when done (default: yes).\n" + " --copy create a copy of backup folder before restoring.\n" + " --settings restore device settings from the backup.\n" + " --remove remove items which are not being restored\n" + " --skip-apps do not trigger re-installation of apps after restore\n" + " --password PWD supply the password for the encrypted source backup\n" + " info show details about last completed backup of device\n" + " list list files of last completed backup in CSV format\n" + " unback unpack a completed backup in DIRECTORY/_unback_/\n" + " encryption on|off [PWD] enable or disable backup encryption\n" + " changepw [OLD NEW] change backup password on target device\n" + " cloud on|off enable or disable cloud use (requires iCloud account)\n" + "\n" + "NOTE: Passwords will be requested in interactive mode (-i) if omitted, or can\n" + "be passed via environment variable BACKUP_PASSWORD/BACKUP_PASSWORD_NEW.\n" + "See man page for further details.\n" + "\n" + "OPTIONS:\n" + " -u, --udid UDID target specific device by UDID\n" + " -s, --source UDID use backup data from device specified by UDID\n" + " -n, --network connect to network device\n" + " -i, --interactive request passwords interactively\n" + " -d, --debug enable communication debugging\n" + " -h, --help prints usage information\n" + " -v, --version prints version information\n" + "\n" + "Homepage: <" PACKAGE_URL ">\n" + "Bug Reports: <" PACKAGE_BUGREPORT ">\n" + ); } +#define DEVICE_VERSION(maj, min, patch) ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF)) + int main(int argc, char *argv[]) { idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR; - int i; + int i = 0; char* udid = NULL; char* source_udid = NULL; + int use_network = 0; lockdownd_service_descriptor_t service = NULL; int cmd = -1; int cmd_flags = 0; @@ -1453,7 +1486,46 @@ int main(int argc, char *argv[]) plist_t node_tmp = NULL; plist_t info_plist = NULL; plist_t opts = NULL; + + idevice_t device = NULL; + afc_client_t afc = NULL; + np_client_t np = NULL; + lockdownd_client_t lockdown = NULL; + mobilebackup2_client_t mobilebackup2 = NULL; mobilebackup2_error_t err; + uint64_t lockfile = 0; + +#define OPT_SYSTEM 1 +#define OPT_REBOOT 2 +#define OPT_NO_REBOOT 3 +#define OPT_COPY 4 +#define OPT_SETTINGS 5 +#define OPT_REMOVE 6 +#define OPT_SKIP_APPS 7 +#define OPT_PASSWORD 8 +#define OPT_FULL 9 + + int c = 0; + const struct option longopts[] = { + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "udid", required_argument, NULL, 'u' }, + { "source", required_argument, NULL, 's' }, + { "interactive", no_argument, NULL, 'i' }, + { "network", no_argument, NULL, 'n' }, + { "version", no_argument, NULL, 'v' }, + // command options: + { "system", no_argument, NULL, OPT_SYSTEM }, + { "reboot", no_argument, NULL, OPT_REBOOT }, + { "no-reboot", no_argument, NULL, OPT_NO_REBOOT }, + { "copy", no_argument, NULL, OPT_COPY }, + { "settings", no_argument, NULL, OPT_SETTINGS }, + { "remove", no_argument, NULL, OPT_REMOVE }, + { "skip-apps", no_argument, NULL, OPT_SKIP_APPS }, + { "password", required_argument, NULL, OPT_PASSWORD }, + { "full", no_argument, NULL, OPT_FULL }, + { NULL, 0, NULL, 0} + }; /* we need to exit cleanly on running backups and restores or we cause havok */ signal(SIGINT, clean_exit); @@ -1464,212 +1536,207 @@ int main(int argc, char *argv[]) #endif /* parse cmdline args */ - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { + while ((c = getopt_long(argc, argv, "dhu:s:inv", longopts, NULL)) != -1) { + switch (c) { + case 'd': idevice_set_debug_level(1); - continue; - } - else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) { - i++; - if (!argv[i] || !*argv[i]) { - print_usage(argc, argv); - return -1; + break; + case 'u': + if (!*optarg) { + fprintf(stderr, "ERROR: UDID argument must not be empty!\n"); + print_usage(argc, argv, 1); + return 2; } - udid = strdup(argv[i]); - continue; - } - else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--source")) { - i++; - if (!argv[i] || !*argv[i]) { - print_usage(argc, argv); - return -1; + udid = strdup(optarg); + break; + case 's': + if (!*optarg) { + fprintf(stderr, "ERROR: SOURCE argument must not be empty!\n"); + print_usage(argc, argv, 1); + return 2; } - source_udid = strdup(argv[i]); - continue; - } - else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--interactive")) { + source_udid = strdup(optarg); + break; + case 'i': interactive_mode = 1; - continue; - } - else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { - print_usage(argc, argv); + break; + case 'n': + use_network = 1; + break; + case 'h': + print_usage(argc, argv, 0); return 0; - } - else if (!strcmp(argv[i], "backup")) { - cmd = CMD_BACKUP; - } - else if (!strcmp(argv[i], "restore")) { - cmd = CMD_RESTORE; - } - else if (!strcmp(argv[i], "--system")) { + case 'v': + printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); + return 0; + case OPT_SYSTEM: cmd_flags |= CMD_FLAG_RESTORE_SYSTEM_FILES; - } - else if (!strcmp(argv[i], "--reboot")) { + break; + case OPT_REBOOT: cmd_flags &= ~CMD_FLAG_RESTORE_NO_REBOOT; - } - else if (!strcmp(argv[i], "--no-reboot")) { + break; + case OPT_NO_REBOOT: cmd_flags |= CMD_FLAG_RESTORE_NO_REBOOT; - } - else if (!strcmp(argv[i], "--copy")) { + break; + case OPT_COPY: cmd_flags |= CMD_FLAG_RESTORE_COPY_BACKUP; - } - else if (!strcmp(argv[i], "--settings")) { + break; + case OPT_SETTINGS: cmd_flags |= CMD_FLAG_RESTORE_SETTINGS; - } - else if (!strcmp(argv[i], "--remove")) { + break; + case OPT_REMOVE: cmd_flags |= CMD_FLAG_RESTORE_REMOVE_ITEMS; - } - else if (!strcmp(argv[i], "--skip-apps")) { + break; + case OPT_SKIP_APPS: cmd_flags |= CMD_FLAG_RESTORE_SKIP_APPS; - } - else if (!strcmp(argv[i], "--password")) { - i++; - if (!argv[i]) { - print_usage(argc, argv); - return -1; - } - if (backup_password) - free(backup_password); - backup_password = strdup(argv[i]); - continue; - } - else if (!strcmp(argv[i], "cloud")) { - cmd = CMD_CLOUD; - i++; - if (!argv[i]) { - printf("No argument given for cloud command; requires either 'on' or 'off'.\n"); - print_usage(argc, argv); - return -1; - } - if (!strcmp(argv[i], "on")) { - cmd_flags |= CMD_FLAG_CLOUD_ENABLE; - } else if (!strcmp(argv[i], "off")) { - cmd_flags |= CMD_FLAG_CLOUD_DISABLE; - } else { - printf("Invalid argument '%s' for cloud command; must be either 'on' or 'off'.\n", argv[i]); - } - continue; - } - else if (!strcmp(argv[i], "--full")) { + break; + case OPT_PASSWORD: + free(backup_password); + backup_password = strdup(optarg); + break; + case OPT_FULL: cmd_flags |= CMD_FLAG_FORCE_FULL_BACKUP; + break; + default: + print_usage(argc, argv, 1); + return 2; } - else if (!strcmp(argv[i], "info")) { - cmd = CMD_INFO; - verbose = 0; - } - else if (!strcmp(argv[i], "list")) { - cmd = CMD_LIST; - verbose = 0; + } + argc -= optind; + argv += optind; + + if (!argv[0]) { + fprintf(stderr, "ERROR: No command specified.\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + + if (!strcmp(argv[0], "backup")) { + cmd = CMD_BACKUP; + } + else if (!strcmp(argv[0], "restore")) { + cmd = CMD_RESTORE; + } + else if (!strcmp(argv[0], "cloud")) { + cmd = CMD_CLOUD; + i = 1; + if (!argv[i]) { + fprintf(stderr, "ERROR: No argument given for cloud command; requires either 'on' or 'off'.\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; } - else if (!strcmp(argv[i], "unback")) { - cmd = CMD_UNBACK; + if (!strcmp(argv[i], "on")) { + cmd_flags |= CMD_FLAG_CLOUD_ENABLE; + } else if (!strcmp(argv[i], "off")) { + cmd_flags |= CMD_FLAG_CLOUD_DISABLE; + } else { + fprintf(stderr, "ERROR: Invalid argument '%s' for cloud command; must be either 'on' or 'off'.\n", argv[i]); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + } + else if (!strcmp(argv[0], "info")) { + cmd = CMD_INFO; + verbose = 0; + } + else if (!strcmp(argv[0], "list")) { + cmd = CMD_LIST; + verbose = 0; + } + else if (!strcmp(argv[0], "unback")) { + cmd = CMD_UNBACK; + } + else if (!strcmp(argv[0], "encryption")) { + cmd = CMD_CHANGEPW; + i = 1; + if (!argv[i]) { + fprintf(stderr, "ERROR: No argument given for encryption command; requires either 'on' or 'off'.\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + if (!strcmp(argv[i], "on")) { + cmd_flags |= CMD_FLAG_ENCRYPTION_ENABLE; + } else if (!strcmp(argv[i], "off")) { + cmd_flags |= CMD_FLAG_ENCRYPTION_DISABLE; + } else { + fprintf(stderr, "ERROR: Invalid argument '%s' for encryption command; must be either 'on' or 'off'.\n", argv[i]); + print_usage(argc+optind, argv-optind, 1); + return 2; } - else if (!strcmp(argv[i], "encryption")) { - cmd = CMD_CHANGEPW; - i++; - if (!argv[i]) { - printf("No argument given for encryption command; requires either 'on' or 'off'.\n"); - print_usage(argc, argv); - return -1; - } - if (!strcmp(argv[i], "on")) { - cmd_flags |= CMD_FLAG_ENCRYPTION_ENABLE; - } else if (!strcmp(argv[i], "off")) { - cmd_flags |= CMD_FLAG_ENCRYPTION_DISABLE; - } else { - printf("Invalid argument '%s' for encryption command; must be either 'on' or 'off'.\n", argv[i]); - } - // check if a password was given on the command line - if (newpw) { - free(newpw); - newpw = NULL; - } - if (backup_password) { - free(backup_password); - backup_password = NULL; - } - i++; - if (argv[i]) { - if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) { - newpw = strdup(argv[i]); - } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) { - backup_password = strdup(argv[i]); - } + // check if a password was given on the command line + free(newpw); + newpw = NULL; + free(backup_password); + backup_password = NULL; + i++; + if (argv[i]) { + if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) { + newpw = strdup(argv[i]); + } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) { + backup_password = strdup(argv[i]); } - continue; } - else if (!strcmp(argv[i], "changepw")) { - cmd = CMD_CHANGEPW; - cmd_flags |= CMD_FLAG_ENCRYPTION_CHANGEPW; - // check if passwords were given on command line - if (newpw) { - free(newpw); - newpw = NULL; - } - if (backup_password) { - free(backup_password); - backup_password = NULL; - } + } + else if (!strcmp(argv[0], "changepw")) { + cmd = CMD_CHANGEPW; + cmd_flags |= CMD_FLAG_ENCRYPTION_CHANGEPW; + // check if passwords were given on command line + free(newpw); + newpw = NULL; + free(backup_password); + backup_password = NULL; + i = 1; + if (argv[i]) { + backup_password = strdup(argv[i]); i++; - if (argv[i]) { - backup_password = strdup(argv[i]); - i++; - if (!argv[i]) { - printf("Old and new passwords have to be passed as arguments for the changepw command\n"); - print_usage(argc, argv); - return -1; - } - newpw = strdup(argv[i]); + if (!argv[i]) { + fprintf(stderr, "ERROR: Old and new passwords have to be passed as arguments for the changepw command\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; } - continue; - } - else if (backup_directory == NULL) { - backup_directory = argv[i]; - } - else { - print_usage(argc, argv); - return -1; + newpw = strdup(argv[i]); } } + i++; + if (argv[i]) { + backup_directory = argv[i]; + } + /* verify options */ if (cmd == -1) { - printf("No command specified.\n"); - print_usage(argc, argv); - return -1; + fprintf(stderr, "ERROR: Unsupported command '%s'.\n", argv[0]); + print_usage(argc+optind, argv-optind, 1); + return 2; } if (cmd == CMD_CHANGEPW || cmd == CMD_CLOUD) { backup_directory = (char*)".this_folder_is_not_present_on_purpose"; } else { if (backup_directory == NULL) { - printf("No target backup directory specified.\n"); - print_usage(argc, argv); - return -1; + fprintf(stderr, "ERROR: No target backup directory specified.\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; } /* verify if passed backup directory exists */ if (stat(backup_directory, &st) != 0) { - printf("ERROR: Backup directory \"%s\" does not exist!\n", backup_directory); + fprintf(stderr, "ERROR: Backup directory \"%s\" does not exist!\n", backup_directory); return -1; } } - idevice_t device = NULL; - if (udid) { - ret = idevice_new(&device, udid); - if (ret != IDEVICE_E_SUCCESS) { - printf("No device found with udid %s, is it plugged in?\n", udid); - return -1; + ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); + if (ret != IDEVICE_E_SUCCESS) { + if (udid) { + printf("No device found with udid %s.\n", udid); + } else { + printf("No device found.\n"); } + return -1; } - else - { - ret = idevice_new(&device, NULL); - if (ret != IDEVICE_E_SUCCESS) { - printf("No device found, is it plugged in?\n"); - return -1; - } + + if (!udid) { idevice_get_udid(device, &udid); } @@ -1680,6 +1747,20 @@ int main(int argc, char *argv[]) uint8_t is_encrypted = 0; char *info_path = NULL; if (cmd == CMD_CHANGEPW) { + if (!interactive_mode) { + if (!newpw) { + newpw = getenv("BACKUP_PASSWORD_NEW"); + if (newpw) { + newpw = strdup(newpw); + } + } + if (!backup_password) { + backup_password = getenv("BACKUP_PASSWORD"); + if (backup_password) { + backup_password = strdup(backup_password); + } + } + } if (!interactive_mode && !backup_password && !newpw) { idevice_free(device); printf("ERROR: Can't get password input in non-interactive mode. Either pass password(s) on the command line, or enable interactive mode with -i or --interactive.\n"); @@ -1700,7 +1781,7 @@ int main(int argc, char *argv[]) free(info_path); } plist_t manifest_plist = NULL; - plist_read_from_filename(&manifest_plist, manifest_path); + plist_read_from_file(manifest_path, &manifest_plist, NULL); if (!manifest_plist) { idevice_free(device); free(info_path); @@ -1721,6 +1802,12 @@ int main(int argc, char *argv[]) if (cmd != CMD_CLOUD && is_encrypted) { PRINT_VERBOSE(1, "This is an encrypted backup.\n"); if (backup_password == NULL) { + backup_password = getenv("BACKUP_PASSWORD"); + if (backup_password) { + backup_password = strdup(backup_password); + } + } + if (backup_password == NULL) { if (interactive_mode) { backup_password = ask_for_password("Enter backup password", 0); } @@ -1739,8 +1826,7 @@ int main(int argc, char *argv[]) } } - lockdownd_client_t lockdown = NULL; - if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lockdown, "idevicebackup2"))) { + if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) { printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret); idevice_free(device); return -1; @@ -1757,8 +1843,26 @@ int main(int argc, char *argv[]) node_tmp = NULL; } + /* get ProductVersion */ + char *product_version = NULL; + int device_version = 0; + node_tmp = NULL; + lockdownd_get_value(lockdown, NULL, "ProductVersion", &node_tmp); + if (node_tmp) { + if (plist_get_node_type(node_tmp) == PLIST_STRING) { + plist_get_string_val(node_tmp, &product_version); + } + plist_free(node_tmp); + node_tmp = NULL; + } + if (product_version) { + int vers[3] = { 0, 0, 0 }; + if (sscanf(product_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) { + device_version = DEVICE_VERSION(vers[0], vers[1], vers[2]); + } + } + /* start notification_proxy */ - np_client_t np = NULL; ldret = lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service); if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) { np_client_new(device, service, &np); @@ -1772,17 +1876,24 @@ int main(int argc, char *argv[]) }; np_observe_notifications(np, noties); } else { - printf("ERROR: Could not start service %s.\n", NP_SERVICE_NAME); + printf("ERROR: Could not start service %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret)); + cmd = CMD_LEAVE; + goto checkpoint; + } + if (service) { + lockdownd_service_descriptor_free(service); + service = NULL; } - afc_client_t afc = NULL; if (cmd == CMD_BACKUP || cmd == CMD_RESTORE) { /* start AFC, we need this for the lock file */ - service->port = 0; - service->ssl_enabled = 0; ldret = lockdownd_start_service(lockdown, AFC_SERVICE_NAME, &service); if ((ldret == LOCKDOWN_E_SUCCESS) && service->port) { afc_client_new(device, service, &afc); + } else { + printf("ERROR: Could not start service %s: %s\n", AFC_SERVICE_NAME, lockdownd_strerror(ldret)); + cmd = CMD_LEAVE; + goto checkpoint; } } @@ -1792,7 +1903,6 @@ int main(int argc, char *argv[]) } /* start mobilebackup service and retrieve port */ - mobilebackup2_client_t mobilebackup2 = NULL; ldret = lockdownd_start_service_with_escrow_bag(lockdown, MOBILEBACKUP2_SERVICE_NAME, &service); lockdownd_client_free(lockdown); lockdown = NULL; @@ -1827,7 +1937,7 @@ int main(int argc, char *argv[]) /* verify existing Info.plist */ if (info_path && (stat(info_path, &st) == 0) && cmd != CMD_CLOUD) { PRINT_VERBOSE(1, "Reading Info.plist from backup.\n"); - plist_read_from_filename(&info_plist, info_path); + plist_read_from_file(info_path, &info_plist, NULL); if (!info_plist) { printf("Could not read Info.plist\n"); @@ -1842,7 +1952,6 @@ int main(int argc, char *argv[]) } } - uint64_t lockfile = 0; if (cmd == CMD_BACKUP || cmd == CMD_RESTORE) { do_post_notification(device, NP_SYNC_WILL_START); afc_file_open(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &lockfile); @@ -1855,15 +1964,16 @@ int main(int argc, char *argv[]) if (aerr == AFC_E_SUCCESS) { do_post_notification(device, NP_SYNC_DID_START); break; - } else if (aerr == AFC_E_OP_WOULD_BLOCK) { + } + if (aerr == AFC_E_OP_WOULD_BLOCK) { usleep(LOCK_WAIT); continue; - } else { - fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr); - afc_file_close(afc, lockfile); - lockfile = 0; - cmd = CMD_LEAVE; } + + fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr); + afc_file_close(afc, lockfile); + lockfile = 0; + cmd = CMD_LEAVE; } if (i == LOCK_ATTEMPTS) { fprintf(stderr, "ERROR: timeout while locking for sync\n"); @@ -1921,7 +2031,7 @@ checkpoint: cmd = CMD_LEAVE; } remove_file(info_path); - plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); + plist_write_to_file(info_plist, info_path, PLIST_FORMAT_XML, 0); free(info_path); plist_free(info_plist); @@ -1982,9 +2092,8 @@ checkpoint: PRINT_VERBOSE(1, "Don't copy backup: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_COPY_BACKUP) == 0 ? "Yes":"No")); plist_dict_set_item(opts, "RestorePreserveSettings", plist_new_bool((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0)); PRINT_VERBOSE(1, "Preserve settings of device: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0 ? "Yes":"No")); - if (cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS) - plist_dict_set_item(opts, "RemoveItemsNotRestored", plist_new_bool(1)); - PRINT_VERBOSE(1, "Remove items that are not restored: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS) ? "Yes":"No")); + plist_dict_set_item(opts, "RemoveItemsNotRestored", plist_new_bool(cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS)); + PRINT_VERBOSE(1, "Remove items that are not restored: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS) ? "Yes":"No")); if (backup_password != NULL) { plist_dict_set_item(opts, "Password", plist_new_string(backup_password)); } @@ -1998,9 +2107,8 @@ checkpoint: if (write_restore_applications(info_plist, afc) < 0) { cmd = CMD_LEAVE; break; - } else { - PRINT_VERBOSE(1, "Wrote RestoreApplications.plist\n"); } + PRINT_VERBOSE(1, "Wrote RestoreApplications.plist\n"); } /* Start restore */ @@ -2055,6 +2163,12 @@ checkpoint: if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) { if (!willEncrypt) { if (!newpw) { + newpw = getenv("BACKUP_PASSWORD"); + if (newpw) { + newpw = strdup(newpw); + } + } + if (!newpw) { newpw = ask_for_password("Enter new backup password", 1); } if (!newpw) { @@ -2071,6 +2185,12 @@ checkpoint: } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) { if (willEncrypt) { if (!backup_password) { + backup_password = getenv("BACKUP_PASSWORD"); + if (backup_password) { + backup_password = strdup(backup_password); + } + } + if (!backup_password) { backup_password = ask_for_password("Enter current backup password", 0); } } else { @@ -2108,6 +2228,32 @@ checkpoint: } if (newpw || backup_password) { mobilebackup2_send_message(mobilebackup2, "ChangePassword", opts); + uint8_t passcode_hint = 0; + if (device_version >= DEVICE_VERSION(13,0,0)) { + diagnostics_relay_client_t diag = NULL; + if (diagnostics_relay_client_start_service(device, &diag, TOOL_NAME) == DIAGNOSTICS_RELAY_E_SUCCESS) { + plist_t dict = NULL; + plist_t keys = plist_new_array(); + plist_array_append_item(keys, plist_new_string("PasswordConfigured")); + if (diagnostics_relay_query_mobilegestalt(diag, keys, &dict) == DIAGNOSTICS_RELAY_E_SUCCESS) { + plist_t node = plist_access_path(dict, 2, "MobileGestalt", "PasswordConfigured"); + plist_get_bool_val(node, &passcode_hint); + } + plist_free(keys); + plist_free(dict); + diagnostics_relay_goodbye(diag); + diagnostics_relay_client_free(diag); + } + } + if (passcode_hint) { + if (cmd_flags & CMD_FLAG_ENCRYPTION_CHANGEPW) { + PRINT_VERBOSE(1, "Please confirm changing the backup password by entering the passcode on the device.\n"); + } else if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) { + PRINT_VERBOSE(1, "Please confirm enabling the backup encryption by entering the passcode on the device.\n"); + } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) { + PRINT_VERBOSE(1, "Please confirm disabling the backup encryption by entering the passcode on the device.\n"); + } + } /*if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) { int retr = 10; while ((retr-- >= 0) && !backup_domain_changed) { @@ -2128,6 +2274,7 @@ checkpoint: int operation_ok = 0; plist_t message = NULL; + mobilebackup2_error_t mberr; char *dlmsg = NULL; int file_count = 0; int errcode = 0; @@ -2138,10 +2285,13 @@ checkpoint: do { free(dlmsg); dlmsg = NULL; - mobilebackup2_receive_message(mobilebackup2, &message, &dlmsg); - if (!message || !dlmsg) { - PRINT_VERBOSE(1, "Device is not ready yet. Going to try again in 2 seconds...\n"); - sleep(2); + mberr = mobilebackup2_receive_message(mobilebackup2, &message, &dlmsg); + if (mberr == MOBILEBACKUP2_E_RECEIVE_TIMEOUT) { + PRINT_VERBOSE(2, "Device is not ready yet, retrying...\n"); + goto files_out; + } else if (mberr != MOBILEBACKUP2_E_SUCCESS) { + PRINT_VERBOSE(0, "ERROR: Could not receive from mobilebackup2 (%d)\n", mberr); + quit_flag++; goto files_out; } @@ -2172,6 +2322,11 @@ checkpoint: plist_t freespace_item = plist_new_uint(freespace); mobilebackup2_send_status_response(mobilebackup2, res, NULL, freespace_item); plist_free(freespace_item); + } else if (!strcmp(dlmsg, "DLMessagePurgeDiskSpace")) { + /* device wants to purge disk space on the host - not supported */ + plist_t empty_dict = plist_new_dict(); + err = mobilebackup2_send_status_response(mobilebackup2, -1, "Operation not supported", empty_dict); + plist_free(empty_dict); } else if (!strcmp(dlmsg, "DLContentsOfDirectory")) { /* list directory contents */ mb2_handle_list_directory(mobilebackup2, message, backup_directory); @@ -2359,7 +2514,7 @@ checkpoint: /* print status */ if ((overall_progress > 0) && !progress_finished) { - if (overall_progress >= 100.0f) { + if (overall_progress >= 100.0F) { progress_finished = 1; } print_progress_real(overall_progress, 0); @@ -2447,12 +2602,18 @@ files_out: } break; case CMD_RESTORE: - if ((cmd_flags & CMD_FLAG_RESTORE_NO_REBOOT) == 0) - PRINT_VERBOSE(1, "The device should reboot now.\n"); if (operation_ok) { + if ((cmd_flags & CMD_FLAG_RESTORE_NO_REBOOT) == 0) + PRINT_VERBOSE(1, "The device should reboot now.\n"); PRINT_VERBOSE(1, "Restore Successful.\n"); } else { - PRINT_VERBOSE(1, "Restore Failed (Error Code %d).\n", -result_code); + afc_remove_path(afc, "/iTunesRestore/RestoreApplications.plist"); + afc_remove_path(afc, "/iTunesRestore"); + if (quit_flag) { + PRINT_VERBOSE(1, "Restore Aborted.\n"); + } else { + PRINT_VERBOSE(1, "Restore Failed (Error Code %d).\n", -result_code); + } } break; case CMD_INFO: @@ -2477,7 +2638,7 @@ files_out: do_post_notification(device, NP_SYNC_DID_FINISH); } } else { - printf("ERROR: Could not start service %s.\n", MOBILEBACKUP2_SERVICE_NAME); + printf("ERROR: Could not start service %s: %s\n", MOBILEBACKUP2_SERVICE_NAME, lockdownd_strerror(ldret)); lockdownd_client_free(lockdown); lockdown = NULL; } |