summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--man/ideviceinstaller.164
-rw-r--r--src/ideviceinstaller.c189
2 files changed, 116 insertions, 137 deletions
diff --git a/man/ideviceinstaller.1 b/man/ideviceinstaller.1
index dbaa0d5..d3849dd 100644
--- a/man/ideviceinstaller.1
+++ b/man/ideviceinstaller.1
@@ -12,11 +12,24 @@ Allows to enumerate, install, upgrade, and uninstall apps on iOS devices.
12.SH COMMANDS 12.SH COMMANDS
13.TP 13.TP
14.B list 14.B list
15List installed apps on the device. 15List installed apps on the device. Options:
16.RS 16.RS
17.TP 17.TP
18\-a|\-\-attribute <attr> 18.B \-\-user
19Specify attribute to return. This argument can be passed multiple times. If omitted and \f[B]-o xml\f[] is *not* specified, the default attributes \f[B]CFBundleIdentifier\f[], \f[B]CFBundleShortVersionString\f[], and \f[B]CFBundleDisplayName\f[] will be used. The attributes can be found in the app's Info.plist, but also some extra attributes exist. Some examples: 19List user apps only (apps installed by the user).
20.B This is the default.
21.TP
22.B \-\-system
23List system apps only (apps available from the system firmware).
24.TP
25.B \-\-all
26List all types of apps.
27.TP
28.B \-\-xml
29Print output as XML Property List.
30.TP
31.B \-a, \-\-attribute ATTR
32Specify attribute to return. This argument can be passed multiple times. If omitted and \f[B]\-\-xml\f[] is *not* specified, the default attributes \f[B]CFBundleIdentifier\f[], \f[B]CFBundleShortVersionString\f[], and \f[B]CFBundleDisplayName\f[] will be used. The attributes can be found in the app's Info.plist, but also some extra attributes exist. Some examples:
20.RS 33.RS
21.TP 34.TP
22\f[B]StaticDiskUsage\f[] disk usage of installed app 35\f[B]StaticDiskUsage\f[] disk usage of installed app
@@ -26,23 +39,12 @@ Specify attribute to return. This argument can be passed multiple times. If omit
26\f[B]Path\f[] app installation location 39\f[B]Path\f[] app installation location
27.TP 40.TP
28\f[B]SignerIdentity\f[] code signing identity 41\f[B]SignerIdentity\f[] code signing identity
42.TP
43NOTE: It is suggested to always add CFBundleIdentifier to allow unique identification of the apps.
29.RE 44.RE
30.TP 45.TP
31\-b|--bundle-identifier <bundleID> 46.B \-b, \-\-bundle\-identifier BUNDLEID
32Only query given bundle identifier. This argument can be passed multiple times. 47Only query given bundle identifier. This argument can be passed multiple times.
33.TP
34\-o list_user
35list user apps only (apps installed by the user)
36.B This is the default.
37.TP
38\-o list_system
39list system apps only (apps available from the system firmware)
40.TP
41\-o list_all
42list all types of apps
43.TP
44\-o xml
45print output in xml format (PList)
46.RE 48.RE
47.TP 49.TP
48.B install PATH 50.B install PATH
@@ -62,23 +64,23 @@ Upgrade app from a package file specified by PATH.
62The following commands are non-functional with iOS 7 or later. 64The following commands are non-functional with iOS 7 or later.
63.TP 65.TP
64.B archive BUNDLEID 66.B archive BUNDLEID
65Archive app specified by BUNDLEID. 67Archive app specified by BUNDLEID. Options:
66.RS 68.RS
67.TP 69.TP
68\-o uninstall 70.B \-\-uninstall
69uninstall the package after making an archive 71Uninstall the package after making an archive
70.TP 72.TP
71\-o app_only 73.B \-\-app_only
72archive application data only 74Archive application data only
73.TP 75.TP
74\-o docs_only 76.B \-\-docs_only
75archive documents (user data) only 77Archive documents (user data) only
76.TP 78.TP
77\-o copy=PATH 79.B \-\-copy=PATH
78copy the app archive to directory PATH when done 80Copy the app archive to directory PATH when done
79.TP 81.TP
80\-o remove 82.B \-\-remove
81only valid when copy=PATH is used: remove after copy 83Only valid when copy=PATH is used: remove after copy
82.RE 84.RE
83 85
84.TP 86.TP
@@ -87,11 +89,11 @@ Restore archived app specified by BUNDLEID.
87 89
88.TP 90.TP
89.B list-archives 91.B list-archives
90List archived apps on the device. 92List archived apps on the device. Options:
91.RS 93.RS
92.TP 94.TP
93\-o xml 95.B \-\-xml
94print full output as xml plist 96Print output as XML Property List.
95.RE 97.RE
96 98
97.TP 99.TP
diff --git a/src/ideviceinstaller.c b/src/ideviceinstaller.c
index ecf63c6..dfa3e13 100644
--- a/src/ideviceinstaller.c
+++ b/src/ideviceinstaller.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * ideviceinstaller - Manage apps on iOS devices. 2 * ideviceinstaller - Manage apps on iOS devices.
3 * 3 *
4 * Copyright (C) 2010-2019 Nikias Bassen <nikias@gmx.li> 4 * Copyright (C) 2010-2023 Nikias Bassen <nikias@gmx.li>
5 * Copyright (C) 2010-2015 Martin Szulecki <m.szulecki@libimobiledevice.org> 5 * Copyright (C) 2010-2015 Martin Szulecki <m.szulecki@libimobiledevice.org>
6 * 6 *
7 * Licensed under the GNU General Public License Version 2 7 * Licensed under the GNU General Public License Version 2
@@ -93,7 +93,6 @@ const char PKG_PATH[] = "PublicStaging";
93const char APPARCH_PATH[] = "ApplicationArchives"; 93const char APPARCH_PATH[] = "ApplicationArchives";
94 94
95char *udid = NULL; 95char *udid = NULL;
96char *options = NULL;
97char *cmdarg = NULL; 96char *cmdarg = NULL;
98 97
99enum cmd_mode { 98enum cmd_mode {
@@ -122,7 +121,14 @@ int err_occurred = 0;
122int notified = 0; 121int notified = 0;
123plist_t bundle_ids = NULL; 122plist_t bundle_ids = NULL;
124plist_t return_attrs = NULL; 123plist_t return_attrs = NULL;
125int return_attrs_have_CFBundleIdentifier = 0; 124int xml_mode = 0;
125int opt_list_user = 0;
126int opt_list_system = 0;
127char *copy_path = NULL;
128int remove_after_copy = 0;
129int skip_uninstall = 1;
130int app_only = 0;
131int docs_only = 0;
126 132
127static void print_apps_header() 133static void print_apps_header()
128{ 134{
@@ -414,30 +420,30 @@ static void print_usage(int argc, char **argv, int is_error)
414 "Manage apps on iOS devices.\n" 420 "Manage apps on iOS devices.\n"
415 "\n" 421 "\n"
416 "COMMANDS:\n" 422 "COMMANDS:\n"
417 " list List installed apps\n" 423 " list List installed apps. Options:\n"
424 " --user List user apps only (this is the default)\n"
425 " --system List system apps only\n"
426 " --all List all types of apps\n"
427 " --xml Print output as XML Property List\n"
418 " -a, --attribute ATTR Specify attribute to return - see man page\n" 428 " -a, --attribute ATTR Specify attribute to return - see man page\n"
419 " (can be passed multiple times)\n" 429 " (can be passed multiple times)\n"
420 " -b, --bundle-identifier BUNDLEID Only query given bundle identifier\n" 430 " -b, --bundle-identifier BUNDLEID Only query given bundle identifier\n"
421 " (can be passed multiple times)\n" 431 " (can be passed multiple times)\n"
422 " -o list_user list user apps only (this is the default)\n"
423 " -o list_system list system apps only\n"
424 " -o list_all list all types of apps\n"
425 " -o xml print full output as xml plist\n"
426 " install PATH Install app from package file specified by PATH.\n" 432 " install PATH Install app from package file specified by PATH.\n"
427 " PATH can also be a .ipcc file for carrier bundles.\n" 433 " PATH can also be a .ipcc file for carrier bundles.\n"
428 " uninstall BUNDLEID Uninstall app specified by BUNDLEID.\n" 434 " uninstall BUNDLEID Uninstall app specified by BUNDLEID.\n"
429 " upgrade PATH Upgrade app from package file specified by PATH.\n" 435 " upgrade PATH Upgrade app from package file specified by PATH.\n"
430 "\n" 436 "\n"
431 "LEGACY COMMANDS (non-functional with iOS 7 or later):\n" 437 "LEGACY COMMANDS (non-functional with iOS 7 or later):\n"
432 " archive BUNDLEID Archive app specified by BUNDLEID, possible options:\n" 438 " archive BUNDLEID Archive app specified by BUNDLEID. Options:\n"
433 " -o uninstall uninstall the package after making an archive\n" 439 " --uninstall Uninstall the package after making an archive\n"
434 " -o app_only archive application data only\n" 440 " --app-only Archive application data only\n"
435 " -o docs_only archive documents (user data) only\n" 441 " --docs-only Archive documents (user data) only\n"
436 " -o copy=PATH copy the app archive to directory PATH when done\n" 442 " --copy=PATH Copy the app archive to directory PATH when done\n"
437 " -o remove only valid when copy=PATH is used: remove after copy\n" 443 " --remove Only valid when copy=PATH is used: remove after copy\n"
438 " restore BUNDLEID Restore archived app specified by BUNDLEID\n" 444 " restore BUNDLEID Restore archived app specified by BUNDLEID\n"
439 " list-archives List archived apps\n" 445 " list-archives List archived apps. Options:\n"
440 " -o xml print full output as xml plist\n" 446 " --xml Print output as XML Property List\n"
441 " remove-archive BUNDLEID Remove app archive specified by BUNDLEID\n" 447 " remove-archive BUNDLEID Remove app archive specified by BUNDLEID\n"
442 "\n" 448 "\n"
443 "OPTIONS:\n" 449 "OPTIONS:\n"
@@ -454,24 +460,44 @@ static void print_usage(int argc, char **argv, int is_error)
454 ); 460 );
455} 461}
456 462
463enum numerical_opts {
464 LIST_USER = 1,
465 LIST_SYSTEM,
466 LIST_ALL,
467 ARCHIVE_UNINSTALL,
468 ARCHIVE_APP_ONLY,
469 ARCHIVE_DOCS_ONLY,
470 ARCHIVE_COPY_PATH,
471 ARCHIVE_COPY_REMOVE,
472 OUTPUT_XML
473};
474
457static void parse_opts(int argc, char **argv) 475static void parse_opts(int argc, char **argv)
458{ 476{
459 static struct option longopts[] = { 477 static struct option longopts[] = {
460 { "help", no_argument, NULL, 'h' }, 478 { "help", no_argument, NULL, 'h' },
461 { "udid", required_argument, NULL, 'u' }, 479 { "udid", required_argument, NULL, 'u' },
462 { "network", no_argument, NULL, 'n' }, 480 { "network", no_argument, NULL, 'n' },
463 { "options", required_argument, NULL, 'o' },
464 { "notify-wait", no_argument, NULL, 'w' }, 481 { "notify-wait", no_argument, NULL, 'w' },
465 { "debug", no_argument, NULL, 'd' }, 482 { "debug", no_argument, NULL, 'd' },
466 { "version", no_argument, NULL, 'v' }, 483 { "version", no_argument, NULL, 'v' },
467 { "bundle-identifier", required_argument, NULL, 'b' }, 484 { "bundle-identifier", required_argument, NULL, 'b' },
468 { "attribute", required_argument, NULL, 'a' }, 485 { "attribute", required_argument, NULL, 'a' },
486 { "user", no_argument, NULL, LIST_USER },
487 { "system", no_argument, NULL, LIST_SYSTEM },
488 { "all", no_argument, NULL, LIST_ALL },
489 { "xml", no_argument, NULL, OUTPUT_XML },
490 { "uninstall", no_argument, NULL, ARCHIVE_UNINSTALL },
491 { "app-only", no_argument, NULL, ARCHIVE_APP_ONLY },
492 { "docs-only", no_argument, NULL, ARCHIVE_DOCS_ONLY },
493 { "copy", required_argument, NULL, ARCHIVE_COPY_PATH },
494 { "remove", no_argument, NULL, ARCHIVE_COPY_REMOVE },
469 { NULL, 0, NULL, 0 } 495 { NULL, 0, NULL, 0 }
470 }; 496 };
471 int c; 497 int c;
472 498
473 while (1) { 499 while (1) {
474 c = getopt_long(argc, argv, "hu:o:nwdvb:a:", longopts, (int*)0); 500 c = getopt_long(argc, argv, "hu:nwdvb:a:", longopts, (int*)0);
475 if (c == -1) { 501 if (c == -1) {
476 break; 502 break;
477 } 503 }
@@ -501,9 +527,6 @@ static void parse_opts(int argc, char **argv)
501 return_attrs = plist_new_array(); 527 return_attrs = plist_new_array();
502 } 528 }
503 plist_array_append_item(return_attrs, plist_new_string(optarg)); 529 plist_array_append_item(return_attrs, plist_new_string(optarg));
504 if (!strcmp(optarg, "CFBundleIdentifier")) {
505 return_attrs_have_CFBundleIdentifier = 1;
506 }
507 break; 530 break;
508 case 'b': 531 case 'b':
509 if (!*optarg) { 532 if (!*optarg) {
@@ -516,18 +539,6 @@ static void parse_opts(int argc, char **argv)
516 } 539 }
517 plist_array_append_item(bundle_ids, plist_new_string(optarg)); 540 plist_array_append_item(bundle_ids, plist_new_string(optarg));
518 break; 541 break;
519 case 'o':
520 if (!options) {
521 options = strdup(optarg);
522 } else {
523 char *newopts = malloc(strlen(options) + strlen(optarg) + 2);
524 strcpy(newopts, options);
525 free(options);
526 strcat(newopts, ",");
527 strcat(newopts, optarg);
528 options = newopts;
529 }
530 break;
531 case 'w': 542 case 'w':
532 use_notifier = 1; 543 use_notifier = 1;
533 break; 544 break;
@@ -537,6 +548,36 @@ static void parse_opts(int argc, char **argv)
537 case 'v': 548 case 'v':
538 printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); 549 printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
539 exit(0); 550 exit(0);
551 case LIST_USER:
552 opt_list_user = 1;
553 break;
554 case LIST_SYSTEM:
555 opt_list_system = 1;
556 break;
557 case LIST_ALL:
558 opt_list_user = 1;
559 opt_list_system = 1;
560 break;
561 case OUTPUT_XML:
562 xml_mode = 1;
563 break;
564 case ARCHIVE_UNINSTALL:
565 skip_uninstall = 0;
566 break;
567 case ARCHIVE_APP_ONLY:
568 app_only = 1;
569 docs_only = 0;
570 break;
571 case ARCHIVE_DOCS_ONLY:
572 docs_only = 1;
573 app_only = 0;
574 break;
575 case ARCHIVE_COPY_PATH:
576 copy_path = strdup(optarg);
577 break;
578 case ARCHIVE_COPY_REMOVE:
579 remove_after_copy = 1;
580 break;
540 default: 581 default:
541 print_usage(argc, argv, 1); 582 print_usage(argc, argv, 1);
542 exit(2); 583 exit(2);
@@ -795,46 +836,30 @@ run_again:
795 notification_expected = 0; 836 notification_expected = 0;
796 837
797 if (cmd == CMD_LIST_APPS) { 838 if (cmd == CMD_LIST_APPS) {
798 int xml_mode = 0;
799 plist_t client_opts = instproxy_client_options_new(); 839 plist_t client_opts = instproxy_client_options_new();
800 instproxy_client_options_add(client_opts, "ApplicationType", "User", NULL); 840 instproxy_client_options_add(client_opts, "ApplicationType", "User", NULL);
801 plist_t apps = NULL; 841 plist_t apps = NULL;
802 842
803 /* look for options */ 843 if (opt_list_system && opt_list_user) {
804 if (options) { 844 plist_dict_remove_item(client_opts, "ApplicationType");
805 char *opts = strdup(options); 845 } else if (opt_list_system) {
806 char *elem = strtok(opts, ","); 846 instproxy_client_options_add(client_opts, "ApplicationType", "System", NULL);
807 while (elem) { 847 } else if (opt_list_user) {
808 if (!strcmp(elem, "list_system")) { 848 instproxy_client_options_add(client_opts, "ApplicationType", "User", NULL);
809 instproxy_client_options_add(client_opts, "ApplicationType", "System", NULL);
810 } else if (!strcmp(elem, "list_all")) {
811 plist_dict_remove_item(client_opts, "ApplicationType");
812 } else if (!strcmp(elem, "list_user")) {
813 /* do nothing, we're already set */
814 } else if (!strcmp(elem, "xml")) {
815 xml_mode = 1;
816 }
817 elem = strtok(NULL, ",");
818 }
819 free(opts);
820 } 849 }
821 850
822 if (bundle_ids) { 851 if (bundle_ids) {
823 plist_dict_set_item(client_opts, "BundleIDs", plist_copy(bundle_ids)); 852 plist_dict_set_item(client_opts, "BundleIDs", plist_copy(bundle_ids));
824 } 853 }
825 854
826 if (!xml_mode && !return_attrs) { 855 if (!xml_mode) {
827 return_attrs = plist_new_array(); 856 return_attrs = plist_new_array();
828 plist_array_append_item(return_attrs, plist_new_string("CFBundleIdentifier")); 857 plist_array_append_item(return_attrs, plist_new_string("CFBundleIdentifier"));
829 return_attrs_have_CFBundleIdentifier = 1;
830 plist_array_append_item(return_attrs, plist_new_string("CFBundleShortVersionString")); 858 plist_array_append_item(return_attrs, plist_new_string("CFBundleShortVersionString"));
831 plist_array_append_item(return_attrs, plist_new_string("CFBundleDisplayName")); 859 plist_array_append_item(return_attrs, plist_new_string("CFBundleDisplayName"));
832 } 860 }
833 861
834 if (return_attrs) { 862 if (return_attrs) {
835 if (!return_attrs_have_CFBundleIdentifier) {
836 plist_array_insert_item(return_attrs, plist_new_string("CFBundleIdentifier"), 0);
837 }
838 instproxy_client_options_add(client_opts, "ReturnAttributes", return_attrs, NULL); 863 instproxy_client_options_add(client_opts, "ReturnAttributes", return_attrs, NULL);
839 } 864 }
840 865
@@ -845,7 +870,6 @@ run_again:
845 fprintf(stderr, "ERROR: instproxy_browse returnd an invalid plist!\n"); 870 fprintf(stderr, "ERROR: instproxy_browse returnd an invalid plist!\n");
846 goto leave_cleanup; 871 goto leave_cleanup;
847 } 872 }
848
849 char *xml = NULL; 873 char *xml = NULL;
850 uint32_t len = 0; 874 uint32_t len = 0;
851 875
@@ -1228,21 +1252,8 @@ run_again:
1228 wait_for_command_complete = 1; 1252 wait_for_command_complete = 1;
1229 notification_expected = 0; 1253 notification_expected = 0;
1230 } else if (cmd == CMD_LIST_ARCHIVES) { 1254 } else if (cmd == CMD_LIST_ARCHIVES) {
1231 int xml_mode = 0;
1232 plist_t dict = NULL; 1255 plist_t dict = NULL;
1233 1256
1234 /* look for options */
1235 if (options) {
1236 char *opts = strdup(options);
1237 char *elem = strtok(opts, ",");
1238 while (elem) {
1239 if (!strcmp(elem, "xml")) {
1240 xml_mode = 1;
1241 }
1242 elem = strtok(NULL, ",");
1243 }
1244 }
1245
1246 err = instproxy_lookup_archives(ipc, NULL, &dict); 1257 err = instproxy_lookup_archives(ipc, NULL, &dict);
1247 if (err != INSTPROXY_E_SUCCESS) { 1258 if (err != INSTPROXY_E_SUCCESS) {
1248 fprintf(stderr, "ERROR: lookup_archives returned %d\n", err); 1259 fprintf(stderr, "ERROR: lookup_archives returned %d\n", err);
@@ -1257,7 +1268,6 @@ run_again:
1257 if (xml_mode) { 1268 if (xml_mode) {
1258 char *xml = NULL; 1269 char *xml = NULL;
1259 uint32_t len = 0; 1270 uint32_t len = 0;
1260
1261 plist_to_xml(dict, &xml, &len); 1271 plist_to_xml(dict, &xml, &len);
1262 if (xml) { 1272 if (xml) {
1263 puts(xml); 1273 puts(xml);
@@ -1310,35 +1320,8 @@ run_again:
1310 while (node); 1320 while (node);
1311 plist_free(dict); 1321 plist_free(dict);
1312 } else if (cmd == CMD_ARCHIVE) { 1322 } else if (cmd == CMD_ARCHIVE) {
1313 char *copy_path = NULL;
1314 int remove_after_copy = 0;
1315 int skip_uninstall = 1;
1316 int app_only = 0;
1317 int docs_only = 0;
1318 plist_t client_opts = NULL; 1323 plist_t client_opts = NULL;
1319 1324
1320 /* look for options */
1321 if (options) {
1322 char *opts = strdup(options);
1323 char *elem = strtok(opts, ",");
1324 while (elem) {
1325 if (!strcmp(elem, "uninstall")) {
1326 skip_uninstall = 0;
1327 } else if (!strcmp(elem, "app_only")) {
1328 app_only = 1;
1329 docs_only = 0;
1330 } else if (!strcmp(elem, "docs_only")) {
1331 docs_only = 1;
1332 app_only = 0;
1333 } else if ((strlen(elem) > 5) && !strncmp(elem, "copy=", 5)) {
1334 copy_path = strdup(elem+5);
1335 } else if (!strcmp(elem, "remove")) {
1336 remove_after_copy = 1;
1337 }
1338 elem = strtok(NULL, ",");
1339 }
1340 }
1341
1342 if (skip_uninstall || app_only || docs_only) { 1325 if (skip_uninstall || app_only || docs_only) {
1343 client_opts = instproxy_client_options_new(); 1326 client_opts = instproxy_client_options_new();
1344 if (skip_uninstall) { 1327 if (skip_uninstall) {
@@ -1355,13 +1338,11 @@ run_again:
1355 struct stat fst; 1338 struct stat fst;
1356 if (stat(copy_path, &fst) != 0) { 1339 if (stat(copy_path, &fst) != 0) {
1357 fprintf(stderr, "ERROR: stat: %s: %s\n", copy_path, strerror(errno)); 1340 fprintf(stderr, "ERROR: stat: %s: %s\n", copy_path, strerror(errno));
1358 free(copy_path);
1359 goto leave_cleanup; 1341 goto leave_cleanup;
1360 } 1342 }
1361 1343
1362 if (!S_ISDIR(fst.st_mode)) { 1344 if (!S_ISDIR(fst.st_mode)) {
1363 fprintf(stderr, "ERROR: '%s' is not a directory as expected.\n", copy_path); 1345 fprintf(stderr, "ERROR: '%s' is not a directory as expected.\n", copy_path);
1364 free(copy_path);
1365 goto leave_cleanup; 1346 goto leave_cleanup;
1366 } 1347 }
1367 1348
@@ -1372,7 +1353,6 @@ run_again:
1372 1353
1373 if ((lockdownd_start_service(client, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || !service) { 1354 if ((lockdownd_start_service(client, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || !service) {
1374 fprintf(stderr, "Could not start com.apple.afc!\n"); 1355 fprintf(stderr, "Could not start com.apple.afc!\n");
1375 free(copy_path);
1376 goto leave_cleanup; 1356 goto leave_cleanup;
1377 } 1357 }
1378 1358
@@ -1411,7 +1391,6 @@ run_again:
1411 fprintf(stderr, "Out of memory!?\n"); 1391 fprintf(stderr, "Out of memory!?\n");
1412 goto leave_cleanup; 1392 goto leave_cleanup;
1413 } 1393 }
1414 free(copy_path);
1415 1394
1416 f = fopen(localfile, "wb"); 1395 f = fopen(localfile, "wb");
1417 if (!f) { 1396 if (!f) {
@@ -1509,8 +1488,6 @@ run_again:
1509 /* remove archive if requested */ 1488 /* remove archive if requested */
1510 printf("Removing '%s'\n", cmdarg); 1489 printf("Removing '%s'\n", cmdarg);
1511 cmd = CMD_REMOVE_ARCHIVE; 1490 cmd = CMD_REMOVE_ARCHIVE;
1512 free(options);
1513 options = NULL;
1514 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "ideviceinstaller")) { 1491 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "ideviceinstaller")) {
1515 fprintf(stderr, "Could not connect to lockdownd. Exiting.\n"); 1492 fprintf(stderr, "Could not connect to lockdownd. Exiting.\n");
1516 goto leave_cleanup; 1493 goto leave_cleanup;
@@ -1547,7 +1524,7 @@ leave_cleanup:
1547 idevice_free(device); 1524 idevice_free(device);
1548 1525
1549 free(udid); 1526 free(udid);
1550 free(options); 1527 free(copy_path);
1551 free(bundleidentifier); 1528 free(bundleidentifier);
1552 plist_free(bundle_ids); 1529 plist_free(bundle_ids);
1553 plist_free(return_attrs); 1530 plist_free(return_attrs);