From e4c4660f2ae0f393386965358307e784096c1396 Mon Sep 17 00:00:00 2001 From: Shazron Abdullah Date: Fri, 12 Dec 2014 17:43:50 -0800 Subject: [PATCH 01/14] Cleaned up get_device_hardware_name by using a macro (related to issue #88). This prepares it for adding models that are missing, see: https://theiphonewiki.com/wiki/Models --- ios-deploy.c | 132 ++++++++++++++++++++++----------------------------- 1 file changed, 56 insertions(+), 76 deletions(-) diff --git a/ios-deploy.c b/ios-deploy.c index 156d1bf..852917b 100644 --- a/ios-deploy.c +++ b/ios-deploy.c @@ -312,87 +312,67 @@ CFStringRef copy_xcode_path_for(CFStringRef subPath, CFStringRef search) { } } +#define GET_FRIENDLY_MODEL_NAME(VALUE, INTERNAL_NAME, FRIENDLY_NAME) if (kCFCompareEqualTo == CFStringCompare(VALUE, CFSTR(INTERNAL_NAME), kCFCompareNonliteral)) { return CFSTR( FRIENDLY_NAME); }; + + // Please ensure that device is connected or the name will be unknown const CFStringRef get_device_hardware_name(const AMDeviceRef device) { CFStringRef model = AMDeviceCopyValue(device, 0, CFSTR("HardwareModel")); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("M68AP"), kCFCompareNonliteral)) - return CFSTR("iPhone"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N45AP"), kCFCompareNonliteral)) - return CFSTR("iPod touch"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N82AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 3G"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N72AP"), kCFCompareNonliteral)) - return CFSTR("iPod touch 2G"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N88AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 3GS"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N18AP"), kCFCompareNonliteral)) - return CFSTR("iPod touch 3G"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("K48AP"), kCFCompareNonliteral)) - return CFSTR("iPad"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N90AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 4 (GSM)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N81AP"), kCFCompareNonliteral)) - return CFSTR("iPod touch 4G"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("K66AP"), kCFCompareNonliteral)) - return CFSTR("Apple TV 2G"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N92AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 4 (CDMA)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N90BAP"), kCFCompareNonliteral)) - return CFSTR("iPhone 4 (GSM, revision A)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("K93AP"), kCFCompareNonliteral)) - return CFSTR("iPad 2"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("K94AP"), kCFCompareNonliteral)) - return CFSTR("iPad 2 (GSM)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("K95AP"), kCFCompareNonliteral)) - return CFSTR("iPad 2 (CDMA)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("K93AAP"), kCFCompareNonliteral)) - return CFSTR("iPad 2 (Wi-Fi, revision A)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("P105AP"), kCFCompareNonliteral)) - return CFSTR("iPad mini"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("P106AP"), kCFCompareNonliteral)) - return CFSTR("iPad mini (GSM)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("P107AP"), kCFCompareNonliteral)) - return CFSTR("iPad mini (CDMA)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N94AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 4S"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N41AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 5 (GSM)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N42AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 5 (Global/CDMA)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N48AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 5c (GSM)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N49AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 5c (Global/CDMA)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N51AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 5s (GSM)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N53AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 5s (Global/CDMA)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N61AP"), kCFCompareNonliteral)) - return CFSTR("iPhone 6 (GSM)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("J1AP"), kCFCompareNonliteral)) - return CFSTR("iPad 3"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("J2AP"), kCFCompareNonliteral)) - return CFSTR("iPad 3 (GSM)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("J2AAP"), kCFCompareNonliteral)) - return CFSTR("iPad 3 (CDMA)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("P101AP"), kCFCompareNonliteral)) - return CFSTR("iPad 4"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("P102AP"), kCFCompareNonliteral)) - return CFSTR("iPad 4 (GSM)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("P103AP"), kCFCompareNonliteral)) - return CFSTR("iPad 4 (CDMA)"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("N78AP"), kCFCompareNonliteral)) - return CFSTR("iPod touch 5G"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("A1509"), kCFCompareNonliteral)) - return CFSTR("iPod touch 5G"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("J33AP"), kCFCompareNonliteral)) - return CFSTR("Apple TV 3G"); - if (kCFCompareEqualTo == CFStringCompare(model,CFSTR("J33IAP"), kCFCompareNonliteral)) - return CFSTR("Apple TV 3.1G"); + + // iPod Touch + + GET_FRIENDLY_MODEL_NAME(model, "N45AP", "iPod Touch") + GET_FRIENDLY_MODEL_NAME(model, "N72AP", "iPod Touch 2G") + GET_FRIENDLY_MODEL_NAME(model, "N18AP", "iPod Touch 3G") + GET_FRIENDLY_MODEL_NAME(model, "N81AP", "iPod Touch 4G") + GET_FRIENDLY_MODEL_NAME(model, "N78AP", "iPod Touch 5G") + GET_FRIENDLY_MODEL_NAME(model, "N78AAP", "iPod Touch 5G") + + // iPad + + GET_FRIENDLY_MODEL_NAME(model, "K48AP", "iPad") + GET_FRIENDLY_MODEL_NAME(model, "K93AP", "iPad 2") + GET_FRIENDLY_MODEL_NAME(model, "K94AP", "iPad 2 (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "K95AP", "iPad 2 (CDMA)") + GET_FRIENDLY_MODEL_NAME(model, "K93AAP", "iPad 2 (Wi-Fi, revision A)") + GET_FRIENDLY_MODEL_NAME(model, "J1AP", "iPad 3") + GET_FRIENDLY_MODEL_NAME(model, "J2AP", "iPad 3 (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "J2AAP", "iPad 3 (CDMA)") + GET_FRIENDLY_MODEL_NAME(model, "P101AP", "iPad 4") + GET_FRIENDLY_MODEL_NAME(model, "P102AP", "iPad 4 (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "P103AP", "iPad 4 (CDMA)") + + // iPad Mini + + GET_FRIENDLY_MODEL_NAME(model, "P105AP", "iPad mini") + GET_FRIENDLY_MODEL_NAME(model, "P106AP", "iPad mini (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "P107AP", "iPad mini (CDMA)") + + // Apple TV + + GET_FRIENDLY_MODEL_NAME(model, "K66AP", "Apple TV 2G") + GET_FRIENDLY_MODEL_NAME(model, "J33AP", "Apple TV 3G") + GET_FRIENDLY_MODEL_NAME(model, "J33IAP", "Apple TV 3.1G") + + // iPhone + + GET_FRIENDLY_MODEL_NAME(model, "M68AP", "iPhone") + GET_FRIENDLY_MODEL_NAME(model, "N82AP", "iPhone 3G") + GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 3GS") + GET_FRIENDLY_MODEL_NAME(model, "N90AP", "iPhone 4 (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "N92AP", "iPhone 4 (CDMA)") + GET_FRIENDLY_MODEL_NAME(model, "N90BAP", "iPhone 4 (GSM, revision A)") + GET_FRIENDLY_MODEL_NAME(model, "N94AP", "iPhone 4S") + GET_FRIENDLY_MODEL_NAME(model, "N41AP", "iPhone 5 (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 5 (Global/CDMA)") + GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 5c (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 5c (Global/CDMA)") + GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 5s (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 5s (Global/CDMA)") + GET_FRIENDLY_MODEL_NAME(model, "N61AP", "iPhone 6 (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "N56AP", "iPhone 6 Plus") return model; - //return CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), hwmodel); - //return CFSTR("Unknown Device"); } char * MYCFStringCopyUTF8String(CFStringRef aString) { From e1aacc0ba1aaab2b3acc988baf9130173d2ea16a Mon Sep 17 00:00:00 2001 From: Shazron Abdullah Date: Fri, 12 Dec 2014 17:46:56 -0800 Subject: [PATCH 02/14] Model table typo (copy paste error) for iPhone 5 models. --- ios-deploy.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ios-deploy.c b/ios-deploy.c index 852917b..561aeee 100644 --- a/ios-deploy.c +++ b/ios-deploy.c @@ -364,11 +364,11 @@ const CFStringRef get_device_hardware_name(const AMDeviceRef device) { GET_FRIENDLY_MODEL_NAME(model, "N90BAP", "iPhone 4 (GSM, revision A)") GET_FRIENDLY_MODEL_NAME(model, "N94AP", "iPhone 4S") GET_FRIENDLY_MODEL_NAME(model, "N41AP", "iPhone 5 (GSM)") - GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 5 (Global/CDMA)") - GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 5c (GSM)") - GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 5c (Global/CDMA)") - GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 5s (GSM)") - GET_FRIENDLY_MODEL_NAME(model, "N88AP", "iPhone 5s (Global/CDMA)") + GET_FRIENDLY_MODEL_NAME(model, "N42AP", "iPhone 5 (Global/CDMA)") + GET_FRIENDLY_MODEL_NAME(model, "N48AP", "iPhone 5c (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "N49AP", "iPhone 5c (Global/CDMA)") + GET_FRIENDLY_MODEL_NAME(model, "N51AP", "iPhone 5s (GSM)") + GET_FRIENDLY_MODEL_NAME(model, "N53AP", "iPhone 5s (Global/CDMA)") GET_FRIENDLY_MODEL_NAME(model, "N61AP", "iPhone 6 (GSM)") GET_FRIENDLY_MODEL_NAME(model, "N56AP", "iPhone 6 Plus") From 0dece5157e6db8bff689496c4103fe9f5c0fa877 Mon Sep 17 00:00:00 2001 From: William Dias Date: Mon, 15 Dec 2014 09:28:13 -0200 Subject: [PATCH 03/14] Add installation instructions in README. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 2472d9f..b6f5d4b 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,12 @@ Install and debug iOS apps without using Xcode. Designed to work on un-jailbroke * You need to have a valid iOS development certificate installed. * Xcode 6.1 should be installed +## Installation + +```bash +$ npm install -g ios-deploy +``` + ## Usage Usage: ios-deploy [OPTION]... From e5e2a6349d9d37ad0f5a380768ac52bca598c759 Mon Sep 17 00:00:00 2001 From: Alex Dunn Date: Tue, 23 Dec 2014 04:53:35 -0800 Subject: [PATCH 04/14] Clarify what npm is and how to get it --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index b6f5d4b..07b4d00 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,12 @@ Install and debug iOS apps without using Xcode. Designed to work on un-jailbroke * Xcode 6.1 should be installed ## Installation +ios-deploy installation is made simple using the node.js package manager. If you use [Homebrew](http://brew.sh/), install node.js: +```bash +brew install node +``` +Now install ios-deploy with the node.js package manager: ```bash $ npm install -g ios-deploy ``` From 48f7881a0b02afb4f5033adf7b8194f31c1c2137 Mon Sep 17 00:00:00 2001 From: Shazron Abdullah Date: Mon, 2 Mar 2015 16:04:43 -0800 Subject: [PATCH 05/14] Fixes #105 - ios-deploy --version returns a non-zero exit code --- ios-deploy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios-deploy.c b/ios-deploy.c index 561aeee..23cb958 100644 --- a/ios-deploy.c +++ b/ios-deploy.c @@ -1710,7 +1710,7 @@ int main(int argc, char *argv[]) { break; case 'V': show_version(); - return exitcode_error; + return 0; case 'p': port = atoi(optarg); break; From 05edec95621f6e95e4d627637ca20019d6d38b2b Mon Sep 17 00:00:00 2001 From: Shazron Abdullah Date: Mon, 2 Mar 2015 16:09:07 -0800 Subject: [PATCH 06/14] Fixes #90, #91 - EXC_BAD_ACCESS crash --- ios-deploy.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ios-deploy.c b/ios-deploy.c index 23cb958..5b01125 100644 --- a/ios-deploy.c +++ b/ios-deploy.c @@ -319,6 +319,10 @@ CFStringRef copy_xcode_path_for(CFStringRef subPath, CFStringRef search) { const CFStringRef get_device_hardware_name(const AMDeviceRef device) { CFStringRef model = AMDeviceCopyValue(device, 0, CFSTR("HardwareModel")); + if (model == NULL) { + return CFSTR("Unknown Device"); + } + // iPod Touch GET_FRIENDLY_MODEL_NAME(model, "N45AP", "iPod Touch") From 56abf4e92e390350a79999df277eb6a8cc067a31 Mon Sep 17 00:00:00 2001 From: Shazron Abdullah Date: Mon, 2 Mar 2015 16:15:11 -0800 Subject: [PATCH 07/14] Updated version to 1.4.0 --- ios-deploy.c | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ios-deploy.c b/ios-deploy.c index 5b01125..e1af3c2 100644 --- a/ios-deploy.c +++ b/ios-deploy.c @@ -16,7 +16,7 @@ #include #include "MobileDevice.h" -#define APP_VERSION "1.3.2" +#define APP_VERSION "1.4.0" #define PREP_CMDS_PATH "/tmp/fruitstrap-lldb-prep-cmds-" #define LLDB_SHELL "lldb -s " PREP_CMDS_PATH /* diff --git a/package.json b/package.json index 53b15d9..d6b1d6b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ios-deploy", - "version": "1.3.2", + "version": "1.4.0", "description": "launch iOS apps iOS devices from the command line (Xcode 6)", "main": "ios-deploy", "scripts": { From cab5a31ab5f9752d9fdec1afd6d177bf556115cc Mon Sep 17 00:00:00 2001 From: Ugur Kilic Date: Sat, 7 Mar 2015 16:33:12 +0200 Subject: [PATCH 08/14] =?UTF-8?q?=E2=80=9Cexists=E2=80=9D=20command=20adde?= =?UTF-8?q?d=20to=20check=20if=20an=20app=20with=20given=20bundle=20id=20i?= =?UTF-8?q?s=20installed=20on=20device=20or=20not=20(closes=20#107)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios-deploy.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/ios-deploy.c b/ios-deploy.c index e1af3c2..cad9ec3 100644 --- a/ios-deploy.c +++ b/ios-deploy.c @@ -1274,6 +1274,40 @@ void list_files(AMDeviceRef device) } } +int app_exists(AMDeviceRef device) +{ + if (bundle_id == NULL) { + printf("Bundle id is not specified\n"); + return false; + } + + AMDeviceConnect(device); + assert(AMDeviceIsPaired(device)); + assert(AMDeviceValidatePairing(device) == 0); + assert(AMDeviceStartSession(device) == 0); + + CFStringRef cf_bundle_id = CFStringCreateWithCString(NULL, bundle_id, kCFStringEncodingASCII); + + NSArray *a = [NSArray arrayWithObjects:@"CFBundleIdentifier", nil]; + NSDictionary *optionsDict = [NSDictionary dictionaryWithObject:a forKey:@"ReturnAttributes"]; + CFDictionaryRef options = (CFDictionaryRef)optionsDict; + + CFDictionaryRef result = nil; + afc_error_t resultStatus = AMDeviceLookupApplications(device, options, &result); + assert(resultStatus == 0); + + CFDictionaryRef app_dict = CFDictionaryGetValue(result, cf_bundle_id); + + int appExists = (app_dict == NULL) ? -1 : 0; + + CFRelease(cf_bundle_id); + + assert(AMDeviceStopSession(device) == 0); + assert(AMDeviceDisconnect(device) == 0); + + return appExists; +} + void copy_file_callback(afc_connection* afc_conn_p, const char *name,int file) { const char *local_name=name; @@ -1456,6 +1490,8 @@ void handle_device(AMDeviceRef device) { upload_file(device); } else if (strcmp("download", command) == 0) { download_tree(device); + } else if (strcmp("exists", command) == 0) { + exit(app_exists(device)); } exit(0); } @@ -1636,7 +1672,8 @@ void usage(const char* app) { " -o, --upload upload file\n" " -w, --download download app tree\n" " -2, --to use together with up/download file/tree. specify target\n" - " -V, --version print the executable version \n", + " -V, --version print the executable version \n" + " -e, --exists check if the app with given bundle_id is installed or not \n", app); } @@ -1666,11 +1703,12 @@ int main(int argc, char *argv[]) { { "upload", required_argument, NULL, 'o'}, { "download", optional_argument, NULL, 'w'}, { "to", required_argument, NULL, '2'}, + { "exists", no_argument, NULL, 'e'}, { NULL, 0, NULL, 0 }, }; char ch; - while ((ch = getopt_long(argc, argv, "VmcdvunrILi:b:a:t:g:x:p:1:2:o:l::w::", longopts, NULL)) != -1) + while ((ch = getopt_long(argc, argv, "VmcdvunrILei:b:a:t:g:x:p:1:2:o:l::w::", longopts, NULL)) != -1) { switch (ch) { case 'm': @@ -1742,6 +1780,10 @@ int main(int argc, char *argv[]) { command = "download"; list_root = optarg; break; + case 'e': + command_only = true; + command = "exists"; + break; default: usage(argv[0]); return exitcode_error; From e8829320531f34f66b020d32a6427ce06a3a7813 Mon Sep 17 00:00:00 2001 From: Shazron Abdullah Date: Mon, 6 Apr 2015 13:43:15 -0700 Subject: [PATCH 09/14] Added doc for --exists option --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 07b4d00..b17b272 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Install and debug iOS apps without using Xcode. Designed to work on un-jailbroke * Xcode 6.1 should be installed ## Installation -ios-deploy installation is made simple using the node.js package manager. If you use [Homebrew](http://brew.sh/), install node.js: +ios-deploy installation is made simple using the node.js package manager. If you use [Homebrew](http://brew.sh/), install node.js: ```bash brew install node ``` @@ -34,14 +34,16 @@ $ npm install -g ios-deploy -L, --justlaunch just launch the app and exit lldb -v, --verbose enable verbose output -m, --noinstall directly start debugging without app install (-d not required) - -p, --port port used for device, default: 12345 - -r, --uninstall uninstall the app before install (do not use with -m; app cache and data are cleared) + -p, --port port used for device, default: 12345 + -r, --uninstall uninstall the app before install (do not use with -m; app cache and data are cleared) -1, --bundle_id specify bundle id for list and upload -l, --list list files -o, --upload upload file -w, --download download app tree -2, --to use together with up/download file/tree. specify target - -V, --version print the executable version + -V, --version print the executable version + -e, --exists check if the app with given bundle_id is installed or not + ## Examples @@ -58,7 +60,7 @@ The commands below assume that you have an app called `my.app` with bundle id `b // Upload a file to your app's Documents folder ios-deploy --bundle_id 'bundle.id' --upload test.txt --to Documents/test.txt - + // Download your app's Documents, Library and tmp folders ios-deploy --bundle_id 'bundle.id' --download --to MyDestinationFolder @@ -67,7 +69,10 @@ The commands below assume that you have an app called `my.app` with bundle id `b // deploy and debug your app to a connected device, uninstall the app first ios-deploy --uninstall --debug --bundle my.app - + + // check whether an app by bundle id exists on the device (check return code `echo $?`) + ios-deploy --exists --bundle_id com.apple.mobilemail + ## Demo * The included demo.app represents the minimum required to get code running on iOS. From 54818aae5c897979abb93ca03f47c81a6f2dc104 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Mon, 6 Apr 2015 15:52:17 +0200 Subject: [PATCH 10/14] Number of fixes: - allow to pass command line arguments from (lldb) prompt; - make lldb exit as opposite to relying on kill (which is problematics because it messes up tty settings); - handle event timeout in autoexit_command to avoid endless loop; - use dynamic TCP port and listen on localhost (no need to expose the port to Internet); - close accept socket once connection is established; (fixes #112) --- ios-deploy.c | 104 +++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/ios-deploy.c b/ios-deploy.c index cad9ec3..dfc4d29 100644 --- a/ios-deploy.c +++ b/ios-deploy.c @@ -61,6 +61,7 @@ const char* lldb_prep_noninteractive_cmds = "\ */ #define LLDB_FRUITSTRAP_MODULE CFSTR("\ import lldb\n\ +import os\n\ import sys\n\ import shlex\n\ \n\ @@ -90,13 +91,14 @@ def connect_command(debugger, command, result, internal_dict):\n\ \n\ def run_command(debugger, command, result, internal_dict):\n\ device_app = internal_dict['fruitstrap_device_app']\n\ + args = command.split('--',1)\n\ error = lldb.SBError()\n\ lldb.target.modules[0].SetPlatformFileSpec(lldb.SBFileSpec(device_app))\n\ - lldb.target.Launch(lldb.SBLaunchInfo(shlex.split('{args}')), error)\n\ + lldb.target.Launch(lldb.SBLaunchInfo(shlex.split(args[1] and args[1] or '{args}')), error)\n\ lockedstr = ': Locked'\n\ if lockedstr in str(error):\n\ print('\\nDevice Locked\\n')\n\ - sys.exit(254)\n\ + os._exit(254)\n\ else:\n\ print(str(error))\n\ \n\ @@ -106,12 +108,16 @@ def safequit_command(debugger, command, result, internal_dict):\n\ listener.StartListeningForEvents(process.GetBroadcaster(), lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR)\n\ event = lldb.SBEvent()\n\ while True:\n\ - if listener.WaitForEvent(1, event):\n\ - state = process.GetStateFromEvent(event)\n\ + if listener.WaitForEvent(1, event) and lldb.SBProcess.EventIsProcessEvent(event):\n\ + state = lldb.SBProcess.GetStateFromEvent(event)\n\ else:\n\ - state = lldb.eStateInvalid\n\ - process.Detach()\n\ - sys.exit(0)\n\ + state = process.GetState()\n\ +\n\ + if state == lldb.eStateRunning:\n\ + process.Detach()\n\ + os._exit(0)\n\ + elif state > lldb.eStateRunning:\n\ + os._exit(state)\n\ \n\ def autoexit_command(debugger, command, result, internal_dict):\n\ process = lldb.target.process\n\ @@ -119,10 +125,16 @@ def autoexit_command(debugger, command, result, internal_dict):\n\ listener.StartListeningForEvents(process.GetBroadcaster(), lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR)\n\ event = lldb.SBEvent()\n\ while True:\n\ - if listener.WaitForEvent(1, event):\n\ - state = process.GetStateFromEvent(event)\n\ + if listener.WaitForEvent(1, event) and lldb.SBProcess.EventIsProcessEvent(event):\n\ + state = lldb.SBProcess.GetStateFromEvent(event)\n\ else:\n\ - state = lldb.eStateInvalid\n\ + state = process.GetState()\n\ +\n\ + if state == lldb.eStateExited:\n\ + os._exit(process.GetExitStatus())\n\ + elif state == lldb.eStateStopped:\n\ + debugger.HandleCommand('bt')\n\ + os._exit({exitcode_app_crash})\n\ \n\ stdout = process.GetSTDOUT(1024)\n\ while stdout:\n\ @@ -133,14 +145,6 @@ def autoexit_command(debugger, command, result, internal_dict):\n\ while stderr:\n\ sys.stdout.write(stderr)\n\ stderr = process.GetSTDERR(1024)\n\ -\n\ - if lldb.SBProcess.EventIsProcessEvent(event):\n\ - if state == lldb.eStateExited:\n\ - sys.exit(process.GetExitStatus())\n\ - if state == lldb.eStateStopped:\n\ - debugger.HandleCommand('frame select')\n\ - debugger.HandleCommand('bt')\n\ - sys.exit({exitcode_app_crash})\n\ ") typedef struct am_device * AMDeviceRef; @@ -164,7 +168,7 @@ char *device_id = NULL; char *args = NULL; char *list_root = NULL; int timeout = 0; -int port = 12345; +int port = 0; // 0 means "dynamically assigned" CFStringRef last_path = NULL; service_conn_t gdbfd; pid_t parent = 0; @@ -822,22 +826,9 @@ server_callback (CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef add int res; if (CFDataGetLength (data) == 0) { - // FIXME: Close the socket - //shutdown (CFSocketGetNative (lldb_socket), SHUT_RDWR); - //close (CFSocketGetNative (lldb_socket)); - CFSocketInvalidate(lldb_socket); - CFSocketInvalidate(server_socket); - int mypid = getpid(); - assert((child != 0) && (child != mypid)); //child should not be here - if ((parent != 0) && (parent == mypid) && (child != 0)) - { - if (verbose) - { - printf("Got an empty packet hence killing child (%d) tree\n", child); - } - kill_ptree(child, SIGHUP); - } - exit(exitcode_error); + // close the socket on which we've got end-of-file, the server_socket. + CFSocketInvalidate(s); + CFRelease(s); return; } res = write (CFSocketGetNative (lldb_socket), CFDataGetBytePtr (data), CFDataGetLength (data)); @@ -847,8 +838,12 @@ void lldb_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef a { //printf ("lldb: %s\n", CFDataGetBytePtr (data)); - if (CFDataGetLength (data) == 0) + if (CFDataGetLength (data) == 0) { + // close the socket on which we've got end-of-file, the lldb_socket. + CFSocketInvalidate(s); + CFRelease(s); return; + } write (gdbfd, CFDataGetBytePtr (data), CFDataGetLength (data)); } @@ -859,21 +854,20 @@ void fdvendor_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataR //PRINT ("callback!\n"); lldb_socket = CFSocketCreateWithNative(NULL, socket, kCFSocketDataCallBack, &lldb_callback, NULL); + int flag = 1; + int res = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag)); + assert(res == 0); CFRunLoopAddSource(CFRunLoopGetMain(), CFSocketCreateRunLoopSource(NULL, lldb_socket, 0), kCFRunLoopCommonModes); + + CFSocketInvalidate(s); + CFRelease(s); } void start_remote_debug_server(AMDeviceRef device) { - char buf [256]; - int res, err, i; - char msg [256]; - int chsum, len; - struct stat s; - socklen_t buflen; - struct sockaddr name; - int namelen; - assert(AMDeviceStartService(device, CFSTR("com.apple.debugserver"), &gdbfd, NULL) == 0); - assert (gdbfd); + int res = AMDeviceStartService(device, CFSTR("com.apple.debugserver"), &gdbfd, NULL); + assert(res == 0); + assert(gdbfd > 0); /* * The debugserver connection is through a fd handle, while lldb requires a host/port to connect, so create an intermediate @@ -887,20 +881,24 @@ void start_remote_debug_server(AMDeviceRef device) { addr4.sin_len = sizeof(addr4); addr4.sin_family = AF_INET; addr4.sin_port = htons(port); - addr4.sin_addr.s_addr = htonl(INADDR_ANY); + addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); CFSocketRef fdvendor = CFSocketCreate(NULL, PF_INET, 0, 0, kCFSocketAcceptCallBack, &fdvendor_callback, NULL); - int yes = 1; - setsockopt(CFSocketGetNative(fdvendor), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); - int flag = 1; - res = setsockopt(CFSocketGetNative(fdvendor), IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); - assert (res == 0); + if (port) { + int yes = 1; + setsockopt(CFSocketGetNative(fdvendor), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + } CFDataRef address_data = CFDataCreate(NULL, (const UInt8 *)&addr4, sizeof(addr4)); CFSocketSetAddress(fdvendor, address_data); CFRelease(address_data); + socklen_t addrlen = sizeof(addr4); + res = getsockname(CFSocketGetNative(fdvendor),(struct sockaddr *)&addr4,&addrlen); + assert(res == 0); + port = ntohs(addr4.sin_port); + CFRunLoopAddSource(CFRunLoopGetMain(), CFSocketCreateRunLoopSource(NULL, fdvendor, 0), kCFRunLoopCommonModes); } @@ -1665,7 +1663,7 @@ void usage(const char* app) { " -L, --justlaunch just launch the app and exit lldb\n" " -v, --verbose enable verbose output\n" " -m, --noinstall directly start debugging without app install (-d not required)\n" - " -p, --port port used for device, default: 12345 \n" + " -p, --port port used for device, default: dynamic\n" " -r, --uninstall uninstall the app before install (do not use with -m; app cache and data are cleared) \n" " -1, --bundle_id specify bundle id for list and upload\n" " -l, --list list files\n" From 5efdcae8cec80f6fd15dc31f1b319585ac14b8aa Mon Sep 17 00:00:00 2001 From: Shazron Abdullah Date: Mon, 6 Apr 2015 13:53:56 -0700 Subject: [PATCH 11/14] Incremented version to 1.5.0 --- ios-deploy.c | 125 +++++++++++++++++++++++++-------------------------- package.json | 2 +- 2 files changed, 63 insertions(+), 64 deletions(-) diff --git a/ios-deploy.c b/ios-deploy.c index dfc4d29..0e0b7dd 100644 --- a/ios-deploy.c +++ b/ios-deploy.c @@ -16,7 +16,7 @@ #include #include "MobileDevice.h" -#define APP_VERSION "1.4.0" +#define APP_VERSION "1.5.0" #define PREP_CMDS_PATH "/tmp/fruitstrap-lldb-prep-cmds-" #define LLDB_SHELL "lldb -s " PREP_CMDS_PATH /* @@ -328,16 +328,16 @@ const CFStringRef get_device_hardware_name(const AMDeviceRef device) { } // iPod Touch - + GET_FRIENDLY_MODEL_NAME(model, "N45AP", "iPod Touch") GET_FRIENDLY_MODEL_NAME(model, "N72AP", "iPod Touch 2G") GET_FRIENDLY_MODEL_NAME(model, "N18AP", "iPod Touch 3G") GET_FRIENDLY_MODEL_NAME(model, "N81AP", "iPod Touch 4G") GET_FRIENDLY_MODEL_NAME(model, "N78AP", "iPod Touch 5G") GET_FRIENDLY_MODEL_NAME(model, "N78AAP", "iPod Touch 5G") - + // iPad - + GET_FRIENDLY_MODEL_NAME(model, "K48AP", "iPad") GET_FRIENDLY_MODEL_NAME(model, "K93AP", "iPad 2") GET_FRIENDLY_MODEL_NAME(model, "K94AP", "iPad 2 (GSM)") @@ -349,7 +349,7 @@ const CFStringRef get_device_hardware_name(const AMDeviceRef device) { GET_FRIENDLY_MODEL_NAME(model, "P101AP", "iPad 4") GET_FRIENDLY_MODEL_NAME(model, "P102AP", "iPad 4 (GSM)") GET_FRIENDLY_MODEL_NAME(model, "P103AP", "iPad 4 (CDMA)") - + // iPad Mini GET_FRIENDLY_MODEL_NAME(model, "P105AP", "iPad mini") @@ -357,11 +357,11 @@ const CFStringRef get_device_hardware_name(const AMDeviceRef device) { GET_FRIENDLY_MODEL_NAME(model, "P107AP", "iPad mini (CDMA)") // Apple TV - + GET_FRIENDLY_MODEL_NAME(model, "K66AP", "Apple TV 2G") GET_FRIENDLY_MODEL_NAME(model, "J33AP", "Apple TV 3G") GET_FRIENDLY_MODEL_NAME(model, "J33IAP", "Apple TV 3.1G") - + // iPhone GET_FRIENDLY_MODEL_NAME(model, "M68AP", "iPhone") @@ -407,7 +407,7 @@ CFStringRef get_device_full_name(const AMDeviceRef device) { model_name = NULL; AMDeviceConnect(device); - + device_name = AMDeviceCopyValue(device, 0, CFSTR("DeviceName")), model_name = get_device_hardware_name(device); @@ -418,7 +418,7 @@ CFStringRef get_device_full_name(const AMDeviceRef device) { CFShow(device_name); printf("\n"); free(devName); - + char *mdlName = MYCFStringCopyUTF8String(model_name); printf("Model Name:[%s]\n",mdlName); printf("MM: [%s]\n",CFStringGetCStringPtr(model_name, kCFStringEncodingUTF8)); @@ -658,10 +658,10 @@ CFURLRef copy_device_app_url(AMDeviceRef device, CFStringRef identifier) { @"UIStatusBarHidden", @"UISupportedInterfaceOrientations", nil]; - + NSDictionary *optionsDict = [NSDictionary dictionaryWithObject:a forKey:@"ReturnAttributes"]; CFDictionaryRef options = (CFDictionaryRef)optionsDict; - + afc_error_t resultStatus = AMDeviceLookupApplications(device, options, &result); assert(resultStatus == 0); @@ -717,13 +717,13 @@ void write_lldb_prep_cmds(AMDeviceRef device, CFURLRef disk_app_url) { rangeLLDB.length = CFStringGetLength(pmodule); CFStringFindAndReplace(pmodule, CFSTR("{args}"), cf_args, rangeLLDB, 0); - //printf("write_lldb_prep_cmds:args: [%s][%s]\n", CFStringGetCStringPtr (cmds,kCFStringEncodingMacRoman), + //printf("write_lldb_prep_cmds:args: [%s][%s]\n", CFStringGetCStringPtr (cmds,kCFStringEncodingMacRoman), // CFStringGetCStringPtr(pmodule, kCFStringEncodingMacRoman)); CFRelease(cf_args); } else { CFStringFindAndReplace(cmds, CFSTR("{args}"), CFSTR(""), range, 0); CFStringFindAndReplace(pmodule, CFSTR("{args}"), CFSTR(""), rangeLLDB, 0); - //printf("write_lldb_prep_cmds: [%s][%s]\n", CFStringGetCStringPtr (cmds,kCFStringEncodingMacRoman), + //printf("write_lldb_prep_cmds: [%s][%s]\n", CFStringGetCStringPtr (cmds,kCFStringEncodingMacRoman), // CFStringGetCStringPtr(pmodule, kCFStringEncodingMacRoman)); } range.length = CFStringGetLength(cmds); @@ -974,38 +974,38 @@ void setup_dummy_pipe_on_stdin(int pfd[2]) { void setup_lldb(AMDeviceRef device, CFURLRef url) { CFStringRef device_full_name = get_device_full_name(device), device_interface_name = get_device_interface_name(device); - + AMDeviceConnect(device); assert(AMDeviceIsPaired(device)); assert(AMDeviceValidatePairing(device) == 0); assert(AMDeviceStartSession(device) == 0); - + printf("------ Debug phase ------\n"); - + if(AMDeviceGetInterfaceType(device) == 2) { printf("Cannot debug %s over %s.\n", CFStringGetCStringPtr(device_full_name, CFStringGetSystemEncoding()), CFStringGetCStringPtr(device_interface_name, CFStringGetSystemEncoding())); exit(0); } - + printf("Starting debug of %s connected through %s...\n", CFStringGetCStringPtr(device_full_name, CFStringGetSystemEncoding()), CFStringGetCStringPtr(device_interface_name, CFStringGetSystemEncoding())); - + mount_developer_image(device); // put debugserver on the device start_remote_debug_server(device); // start debugserver write_lldb_prep_cmds(device, url); // dump the necessary lldb commands into a file - + CFRelease(url); - + printf("[100%%] Connecting to remote debug server\n"); printf("-------------------------\n"); - + setpgid(getpid(), 0); signal(SIGHUP, killed); signal(SIGINT, killed); signal(SIGTERM, killed); // Need this before fork to avoid race conditions. For child process we remove this right after fork. signal(SIGLLDB, lldb_finished_handler); - + parent = getpid(); } @@ -1039,7 +1039,7 @@ void launch_debugger(AMDeviceRef device, CFURLRef url) { close(pfd[0]); close(pfd[1]); - + // Notify parent we're exiting kill(parent, SIGLLDB); // Pass lldb exit code @@ -1062,21 +1062,21 @@ void launch_debugger_and_exit(AMDeviceRef device, CFURLRef url) { signal(SIGHUP, SIG_DFL); signal(SIGLLDB, SIG_DFL); child = getpid(); - + if (dup2(pfd[0],STDIN_FILENO) == -1) perror("dup2 failed"); - + char lldb_shell[400]; sprintf(lldb_shell, LLDB_SHELL); if(device_id != NULL) strcat(lldb_shell, device_id); - + int status = system(lldb_shell); // launch lldb if (status == -1) perror("failed launching lldb"); - + close(pfd[0]); - + // Notify parent we're exiting kill(parent, SIGLLDB); // Pass lldb exit code @@ -1127,20 +1127,20 @@ CFStringRef get_bundle_id(CFURLRef app_url) return bundle_id; } - + void read_dir(service_conn_t afcFd, afc_connection* afc_conn_p, const char* dir, void(*callback)(afc_connection *conn,const char *dir,int file)) { char *dir_ent; - + afc_connection afc_conn; if (!afc_conn_p) { afc_conn_p = &afc_conn; AFCConnectionOpen(afcFd, 0, &afc_conn_p); } - + printf("%s\n", dir); - + afc_dictionary* afc_dict_p; char *key, *val; int not_dir = 0; @@ -1150,7 +1150,7 @@ void read_dir(service_conn_t afcFd, afc_connection* afc_conn_p, const char* dir, // there was a problem reading or opening the file to get info on it, abort return; } - + while((AFCKeyValueRead(afc_dict_p,&key,&val) == 0) && key && val) { if (strcmp(key,"st_ifmt")==0) { not_dir = strcmp(val,"S_IFDIR"); @@ -1166,23 +1166,23 @@ void read_dir(service_conn_t afcFd, afc_connection* afc_conn_p, const char* dir, afc_directory* afc_dir_p; afc_error_t err = AFCDirectoryOpen(afc_conn_p, dir, &afc_dir_p); - + if (err != 0) { // Couldn't open dir - was probably a file return; } else { if (callback) (*callback)(afc_conn_p, dir, not_dir); } - + while(true) { err = AFCDirectoryRead(afc_conn_p, afc_dir_p, &dir_ent); - + if (err != 0 || !dir_ent) break; - + if (strcmp(dir_ent, ".") == 0 || strcmp(dir_ent, "..") == 0) continue; - + char* dir_joined = malloc(strlen(dir) + strlen(dir_ent) + 2); strcpy(dir_joined, dir); if (dir_joined[strlen(dir)-1] != '/') @@ -1191,7 +1191,7 @@ void read_dir(service_conn_t afcFd, afc_connection* afc_conn_p, const char* dir, read_dir(afcFd, afc_conn_p, dir_joined, callback); free(dir_joined); } - + AFCDirectoryClose(afc_conn_p, afc_dir_p); } @@ -1202,25 +1202,25 @@ service_conn_t start_house_arrest_service(AMDeviceRef device) { assert(AMDeviceIsPaired(device)); assert(AMDeviceValidatePairing(device) == 0); assert(AMDeviceStartSession(device) == 0); - + service_conn_t houseFd; - + if (bundle_id == NULL) { printf("Bundle id is not specified\n"); exit(1); } - + CFStringRef cf_bundle_id = CFStringCreateWithCString(NULL, bundle_id, kCFStringEncodingASCII); if (AMDeviceStartHouseArrestService(device, cf_bundle_id, 0, &houseFd, 0) != 0) { printf("Unable to find bundle with id: %s\n", bundle_id); exit(1); } - + assert(AMDeviceStopSession(device) == 0); assert(AMDeviceDisconnect(device) == 0); CFRelease(cf_bundle_id); - + return houseFd; } @@ -1248,7 +1248,7 @@ void* read_file_to_memory(char * path, size_t* file_size) { return NULL; } - + *file_size = buf.st_size; FILE* fd = fopen(path, "r"); char* content = malloc(*file_size); @@ -1264,7 +1264,7 @@ void* read_file_to_memory(char * path, size_t* file_size) void list_files(AMDeviceRef device) { service_conn_t houseFd = start_house_arrest_service(device); - + afc_connection* afc_conn_p; if (AFCConnectionOpen(houseFd, 0, &afc_conn_p) == 0) { read_dir(houseFd, afc_conn_p, list_root?list_root:"/", NULL); @@ -1289,7 +1289,7 @@ int app_exists(AMDeviceRef device) NSArray *a = [NSArray arrayWithObjects:@"CFBundleIdentifier", nil]; NSDictionary *optionsDict = [NSDictionary dictionaryWithObject:a forKey:@"ReturnAttributes"]; CFDictionaryRef options = (CFDictionaryRef)optionsDict; - + CFDictionaryRef result = nil; afc_error_t resultStatus = AMDeviceLookupApplications(device, options, &result); assert(resultStatus == 0); @@ -1399,15 +1399,15 @@ void download_tree(AMDeviceRef device) void upload_file(AMDeviceRef device) { service_conn_t houseFd = start_house_arrest_service(device); - + afc_file_ref file_ref; - + afc_connection afc_conn; afc_connection* afc_conn_p = &afc_conn; AFCConnectionOpen(houseFd, 0, &afc_conn_p); - + // read_dir(houseFd, NULL, "/", NULL); - + if (!target_filename) { target_filename = get_filename_from_path(upload_pathname); @@ -1415,7 +1415,7 @@ void upload_file(AMDeviceRef device) { size_t file_size; void* file_content = read_file_to_memory(upload_pathname, &file_size); - + if (!file_content) { printf("Could not open file: %s\n", upload_pathname); @@ -1435,7 +1435,7 @@ void upload_file(AMDeviceRef device) { *lastSlash = '\0'; assert(AFCDirectoryCreate(afc_conn_p, dirpath) == 0); } - + int ret = AFCFileRefOpen(afc_conn_p, target_filename, 3, &file_ref); if (ret == 0x000a) { @@ -1450,12 +1450,12 @@ void upload_file(AMDeviceRef device) { assert(AFCFileRefWrite(afc_conn_p, file_ref, file_content, file_size) == 0); assert(AFCFileRefClose(afc_conn_p, file_ref) == 0); assert(AFCConnectionClose(afc_conn_p) == 0); - + free(file_content); } void handle_device(AMDeviceRef device) { - //if (found_device) + //if (found_device) // return; // handle one device only CFStringRef found_device_id = AMDeviceCopyDeviceIdentifier(device), @@ -1480,7 +1480,7 @@ void handle_device(AMDeviceRef device) { } printf("[....] Using %s (%s).\n", CFStringGetCStringPtr(device_full_name, CFStringGetSystemEncoding()), CFStringGetCStringPtr(found_device_id, CFStringGetSystemEncoding())); - + if (command_only) { if (strcmp("list", command) == 0) { list_files(device); @@ -1514,7 +1514,7 @@ void handle_device(AMDeviceRef device) { assert(AMDeviceIsPaired(device)); assert(AMDeviceValidatePairing(device) == 0); assert(AMDeviceStartSession(device) == 0); - + int code = AMDeviceSecureUninstallApplication(0, device, bundle_id, 0, NULL, 0); if (code == 0) { printf("[ OK ] Uninstalled package with bundle id %s\n", CFStringGetCStringPtr(bundle_id, CFStringGetSystemEncoding())); @@ -1551,7 +1551,7 @@ void handle_device(AMDeviceRef device) { close(afcFd); - + AMDeviceConnect(device); assert(AMDeviceIsPaired(device)); @@ -1587,9 +1587,9 @@ void handle_device(AMDeviceRef device) { printf("[100%%] Installed package %s\n", app_path); } - if (!debug) + if (!debug) exit(0); // no debug phase - + if (justlaunch) launch_debugger_and_exit(device, url); else @@ -1602,7 +1602,7 @@ void device_callback(struct am_device_notification_callback_info *info, void *ar if(device_id != NULL || !debug || AMDeviceGetInterfaceType(info->dev) != 2) { handle_device(info->dev); } else if(best_device_match == NULL) { - best_device_match = info->dev; + best_device_match = info->dev; CFRetain(best_device_match); } default: @@ -1629,7 +1629,7 @@ void timeout_callback(CFRunLoopTimerRef timer, void *info) { if (!debug) { printf("[....] No more devices found.\n"); } - + if (detect_only && !found_device) { exit(exitcode_error); return; @@ -1822,4 +1822,3 @@ int main(int argc, char *argv[]) { AMDeviceNotificationSubscribe(&device_callback, 0, 0, NULL, ¬ify); CFRunLoopRun(); } - diff --git a/package.json b/package.json index d6b1d6b..cd62282 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ios-deploy", - "version": "1.4.0", + "version": "1.5.0", "description": "launch iOS apps iOS devices from the command line (Xcode 6)", "main": "ios-deploy", "scripts": { From c1a0623e493e096a92eaffc8a642c39c8906678e Mon Sep 17 00:00:00 2001 From: Shazron Abdullah Date: Mon, 6 Apr 2015 14:06:52 -0700 Subject: [PATCH 12/14] Added doc to download specific directory (ie Documents) from an installed app (closes #108) --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index b17b272..7e00fea 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,9 @@ The commands below assume that you have an app called `my.app` with bundle id `b // check whether an app by bundle id exists on the device (check return code `echo $?`) ios-deploy --exists --bundle_id com.apple.mobilemail + // Download the Documents directory of the app *only* + ios-deploy --download=/Documents -bundle_id my.app.id --to ./my_download_location + ## Demo * The included demo.app represents the minimum required to get code running on iOS. From 54a04e203f2e8d91939d1e909e38ae69fbf1b297 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 15 Apr 2015 11:42:09 -0400 Subject: [PATCH 13/14] Add --mkdir and --rm options --- ios-deploy.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ios-deploy.c b/ios-deploy.c index 0e0b7dd..9d5c15f 100644 --- a/ios-deploy.c +++ b/ios-deploy.c @@ -1454,6 +1454,33 @@ void upload_file(AMDeviceRef device) { free(file_content); } +void make_directory(AMDeviceRef device) { + service_conn_t houseFd = start_house_arrest_service(device); + + afc_file_ref file_ref; + + afc_connection afc_conn; + afc_connection* afc_conn_p = &afc_conn; + AFCConnectionOpen(houseFd, 0, &afc_conn_p); + + assert(AFCDirectoryCreate(afc_conn_p, target_filename) == 0); + assert(AFCConnectionClose(afc_conn_p) == 0); +} + +void remove_path(AMDeviceRef device) { + service_conn_t houseFd = start_house_arrest_service(device); + + afc_file_ref file_ref; + + afc_connection afc_conn; + afc_connection* afc_conn_p = &afc_conn; + AFCConnectionOpen(houseFd, 0, &afc_conn_p); + + + assert(AFCRemovePath(afc_conn_p, target_filename) == 0); + assert(AFCConnectionClose(afc_conn_p) == 0); +} + void handle_device(AMDeviceRef device) { //if (found_device) // return; // handle one device only @@ -1488,6 +1515,10 @@ void handle_device(AMDeviceRef device) { upload_file(device); } else if (strcmp("download", command) == 0) { download_tree(device); + } else if (strcmp("mkdir", command) == 0) { + make_directory(device); + } else if (strcmp("rm", command) == 0) { + remove_path(device); } else if (strcmp("exists", command) == 0) { exit(app_exists(device)); } @@ -1670,6 +1701,8 @@ void usage(const char* app) { " -o, --upload upload file\n" " -w, --download download app tree\n" " -2, --to use together with up/download file/tree. specify target\n" + " -D, --mkdir make directory on device\n" + " -R, --rm remove file or directory on device (directories must be empty)\n" " -V, --version print the executable version \n" " -e, --exists check if the app with given bundle_id is installed or not \n", app); @@ -1701,6 +1734,8 @@ int main(int argc, char *argv[]) { { "upload", required_argument, NULL, 'o'}, { "download", optional_argument, NULL, 'w'}, { "to", required_argument, NULL, '2'}, + { "mkdir", required_argument, NULL, 'D'}, + { "rm", required_argument, NULL, 'R'}, { "exists", no_argument, NULL, 'e'}, { NULL, 0, NULL, 0 }, }; @@ -1778,6 +1813,16 @@ int main(int argc, char *argv[]) { command = "download"; list_root = optarg; break; + case 'D': + command_only = true; + target_filename = optarg; + command = "mkdir"; + break; + case 'R': + command_only = true; + target_filename = optarg; + command = "rm"; + break; case 'e': command_only = true; command = "exists"; From 8d1f79d27c81fddb0b4929e865920b322e67449b Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 22 Apr 2015 07:43:31 -0400 Subject: [PATCH 14/14] Update README to include --mkdir and --rm --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7e00fea..98906f6 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ $ npm install -g ios-deploy -o, --upload upload file -w, --download download app tree -2, --to use together with up/download file/tree. specify target + -D, --mkdir make directory on device + -R, --rm remove file or directory on device (directories must be empty) -V, --version print the executable version -e, --exists check if the app with given bundle_id is installed or not