diff options
| author | 2023-03-27 01:51:20 +0200 | |
|---|---|---|
| committer | 2023-03-27 01:51:20 +0200 | |
| commit | e86c2e397e7873503f1986faf22a5e592a2c8dc1 (patch) | |
| tree | 53d247ae6b5146a61be662bb481280c9a0e6421e | |
| parent | 9525a2a76171e7da82f0e3fd602ad3c7101a30bf (diff) | |
| download | ideviceinstaller-e86c2e397e7873503f1986faf22a5e592a2c8dc1.tar.gz ideviceinstaller-e86c2e397e7873503f1986faf22a5e592a2c8dc1.tar.bz2 | |
Further rework of command line option handling
| -rw-r--r-- | man/ideviceinstaller.1 | 64 | ||||
| -rw-r--r-- | src/ideviceinstaller.c | 189 |
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 |
| 15 | List installed apps on the device. | 15 | List installed apps on the device. Options: |
| 16 | .RS | 16 | .RS |
| 17 | .TP | 17 | .TP |
| 18 | \-a|\-\-attribute <attr> | 18 | .B \-\-user |
| 19 | Specify 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: | 19 | List user apps only (apps installed by the user). |
| 20 | .B This is the default. | ||
| 21 | .TP | ||
| 22 | .B \-\-system | ||
| 23 | List system apps only (apps available from the system firmware). | ||
| 24 | .TP | ||
| 25 | .B \-\-all | ||
| 26 | List all types of apps. | ||
| 27 | .TP | ||
| 28 | .B \-\-xml | ||
| 29 | Print output as XML Property List. | ||
| 30 | .TP | ||
| 31 | .B \-a, \-\-attribute ATTR | ||
| 32 | Specify 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 | ||
| 43 | NOTE: 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 |
| 32 | Only query given bundle identifier. This argument can be passed multiple times. | 47 | Only query given bundle identifier. This argument can be passed multiple times. |
| 33 | .TP | ||
| 34 | \-o list_user | ||
| 35 | list user apps only (apps installed by the user) | ||
| 36 | .B This is the default. | ||
| 37 | .TP | ||
| 38 | \-o list_system | ||
| 39 | list system apps only (apps available from the system firmware) | ||
| 40 | .TP | ||
| 41 | \-o list_all | ||
| 42 | list all types of apps | ||
| 43 | .TP | ||
| 44 | \-o xml | ||
| 45 | print 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. | |||
| 62 | The following commands are non-functional with iOS 7 or later. | 64 | The following commands are non-functional with iOS 7 or later. |
| 63 | .TP | 65 | .TP |
| 64 | .B archive BUNDLEID | 66 | .B archive BUNDLEID |
| 65 | Archive app specified by BUNDLEID. | 67 | Archive app specified by BUNDLEID. Options: |
| 66 | .RS | 68 | .RS |
| 67 | .TP | 69 | .TP |
| 68 | \-o uninstall | 70 | .B \-\-uninstall |
| 69 | uninstall the package after making an archive | 71 | Uninstall the package after making an archive |
| 70 | .TP | 72 | .TP |
| 71 | \-o app_only | 73 | .B \-\-app_only |
| 72 | archive application data only | 74 | Archive application data only |
| 73 | .TP | 75 | .TP |
| 74 | \-o docs_only | 76 | .B \-\-docs_only |
| 75 | archive documents (user data) only | 77 | Archive documents (user data) only |
| 76 | .TP | 78 | .TP |
| 77 | \-o copy=PATH | 79 | .B \-\-copy=PATH |
| 78 | copy the app archive to directory PATH when done | 80 | Copy the app archive to directory PATH when done |
| 79 | .TP | 81 | .TP |
| 80 | \-o remove | 82 | .B \-\-remove |
| 81 | only valid when copy=PATH is used: remove after copy | 83 | Only 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 |
| 90 | List archived apps on the device. | 92 | List archived apps on the device. Options: |
| 91 | .RS | 93 | .RS |
| 92 | .TP | 94 | .TP |
| 93 | \-o xml | 95 | .B \-\-xml |
| 94 | print full output as xml plist | 96 | Print 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"; | |||
| 93 | const char APPARCH_PATH[] = "ApplicationArchives"; | 93 | const char APPARCH_PATH[] = "ApplicationArchives"; |
| 94 | 94 | ||
| 95 | char *udid = NULL; | 95 | char *udid = NULL; |
| 96 | char *options = NULL; | ||
| 97 | char *cmdarg = NULL; | 96 | char *cmdarg = NULL; |
| 98 | 97 | ||
| 99 | enum cmd_mode { | 98 | enum cmd_mode { |
| @@ -122,7 +121,14 @@ int err_occurred = 0; | |||
| 122 | int notified = 0; | 121 | int notified = 0; |
| 123 | plist_t bundle_ids = NULL; | 122 | plist_t bundle_ids = NULL; |
| 124 | plist_t return_attrs = NULL; | 123 | plist_t return_attrs = NULL; |
| 125 | int return_attrs_have_CFBundleIdentifier = 0; | 124 | int xml_mode = 0; |
| 125 | int opt_list_user = 0; | ||
| 126 | int opt_list_system = 0; | ||
| 127 | char *copy_path = NULL; | ||
| 128 | int remove_after_copy = 0; | ||
| 129 | int skip_uninstall = 1; | ||
| 130 | int app_only = 0; | ||
| 131 | int docs_only = 0; | ||
| 126 | 132 | ||
| 127 | static void print_apps_header() | 133 | static 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 | ||
| 463 | enum 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 | |||
| 457 | static void parse_opts(int argc, char **argv) | 475 | static 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); |
