Compare commits
	
		
			31 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 125cd8de64 | ||
|   | 7070623432 | ||
|   | d712420e60 | ||
|   | 2c35b70ff7 | ||
|   | ea8202c506 | ||
|   | 7c1372041d | ||
|   | b67b90be19 | ||
|   | 9156689720 | ||
|   | a89b71bdf4 | ||
|   | 6e4df1cc07 | ||
|   | fc667bc423 | ||
|   | 2119c10455 | ||
|   | 1db084594e | ||
|   | 8d1f79d27c | ||
|   | 8c9dab1564 | ||
|   | 54a04e203f | ||
|   | c1a0623e49 | ||
|   | 5efdcae8ce | ||
|   | 54818aae5c | ||
|   | e882932053 | ||
|   | cab5a31ab5 | ||
|   | 56abf4e92e | ||
|   | 05edec9562 | ||
|   | 48f7881a0b | ||
|   | abbd1a3769 | ||
|   | e5e2a6349d | ||
|   | 5a8d7f9efb | ||
|   | 0dece5157e | ||
|   | e1aacc0ba1 | ||
|   | e4c4660f2a | ||
|   | 33f6a83e1d | 
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,10 +1,10 @@ | ||||
| IOS_SDK_VERSION = 7.1 | ||||
| IOS_SDK_VERSION = 8.3 | ||||
|  | ||||
| IOS_CC = gcc -ObjC | ||||
| DEVICE_SUPPORT = $(shell xcode-select --print-path)/Platforms/iPhoneOS.platform/DeviceSupport | ||||
| IOS_SDK = $(shell xcode-select --print-path)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$(IOS_SDK_VERSION).sdk | ||||
|  | ||||
| all: clean ios-deploy | ||||
| all: clean ios-deploy demo.app | ||||
|  | ||||
| demo.app: demo Info.plist | ||||
| 	mkdir -p demo.app | ||||
| @@ -32,4 +32,4 @@ debug: all | ||||
| 	./ios-deploy --debug --bundle demo.app | ||||
|  | ||||
| clean: | ||||
| 	rm -rf *.app demo ios-deploy | ||||
| 	@rm -rf *.app demo ios-deploy | ||||
|   | ||||
							
								
								
									
										69
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								README.md
									
									
									
									
									
								
							| @@ -4,9 +4,31 @@ Install and debug iOS apps without using Xcode. Designed to work on un-jailbroke | ||||
|  | ||||
| ## Requirements | ||||
|  | ||||
| * Mac OS X. Tested on 10.10 Yosemite and iOS 8.1 | ||||
| * You need to have a valid iOS development certificate installed. | ||||
| * Xcode 6.1 should be installed | ||||
| * Mac OS X. Tested on 10.10 Yosemite and iOS 8.3 | ||||
| * You need to have a valid iOS Development certificate installed. | ||||
| * Xcode 6 or greater 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](https://nodejs.org): | ||||
|  | ||||
| ``` | ||||
| brew install node | ||||
| ``` | ||||
|  | ||||
| Now install ios-deploy with the [node.js](https://nodejs.org) package manager: | ||||
|  | ||||
| ``` | ||||
| npm install -g ios-deploy | ||||
| ``` | ||||
|  | ||||
| To install from source: | ||||
|  | ||||
| ``` | ||||
| make install prefix=/usr/local | ||||
| ``` | ||||
|  | ||||
| This will install ios-deploy in the `bin` folder of `/usr/local`, i.e. `/usr/local/bin` | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| @@ -23,14 +45,19 @@ Install and debug iOS apps without using Xcode. Designed to work on un-jailbroke | ||||
|       -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 <number>          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 <bundle id>  specify bundle id for list and upload | ||||
|       -p, --port <number>          port used for device, default: 12345 | ||||
|       -r, --uninstall              uninstall the app before install (do not use with -m; app cache and data are cleared) | ||||
|       -9, --uninstall_only         uninstall the app ONLY. Use only with -1 <bundle_id>  | ||||
|       -1, --bundle_id <bundle id>  specify bundle id for list, upload, and uninstall_only | ||||
|       -l, --list                   list files | ||||
|       -o, --upload <file>          upload file | ||||
|       -w, --download               download app tree | ||||
|       -2, --to <target pathname>   use together with up/download file/tree. specify target | ||||
|       -V, --version                print the executable version  | ||||
|       -D, --mkdir <dir>            make directory on device | ||||
|       -R, --rm <path>              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 | ||||
|  | ||||
|  | ||||
| ## Examples | ||||
|  | ||||
| @@ -47,7 +74,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 | ||||
|  | ||||
| @@ -56,20 +83,26 @@ 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 | ||||
|  | ||||
|     // Download the Documents directory of the app *only* | ||||
|     ios-deploy --download=/Documents -bundle_id my.app.id --to ./my_download_location | ||||
|      | ||||
|     // List ids and names of connected devices | ||||
|     ios-deploy -c | ||||
|      | ||||
|     // Uninstall an app | ||||
|     ios-deploy --uninstall_only --bundle_id my.bundle.id | ||||
|  | ||||
| ## Demo | ||||
|  | ||||
| * The included demo.app represents the minimum required to get code running on iOS. | ||||
| * `make install` will install demo.app to the device. | ||||
| * `make debug` will install demo.app and launch a GDB session. | ||||
| The included demo.app represents the minimum required to get code running on iOS. | ||||
|  | ||||
| * `make demo.app` will generate the demo.app executable. If it doesn't compile, modify IOS_SDK_VERSION in the Makefile. | ||||
| * `make debug` will install demo.app and launch a LLDB session. | ||||
|  | ||||
| ## Notes | ||||
|  | ||||
| * With some modifications, it may be possible to use this without Xcode installed; however, you would need a copy of the relevant DeveloperDiskImage.dmg (included with Xcode). lldb would also run slower as symbols would be downloaded from the device on-the-fly. | ||||
|  | ||||
|  | ||||
| ## Listing Device Ids | ||||
|  | ||||
| Device Ids are the UDIDs of the iOS devices. From the command line, you can list device ids [this way](http://javierhz.blogspot.com/2012/06/how-to-get-udid-of-iphone-using-shell.html): | ||||
|  | ||||
|         system_profiler SPUSBDataType | sed -n -e '/iPod/,/Serial/p' | sed -n -e '/iPad/,/Serial/p' -e '/iPhone/,/Serial/p' | grep "Serial Number:" | awk -F ": " '{print $2}' | ||||
|   | ||||
							
								
								
									
										517
									
								
								ios-deploy.c
									
									
									
									
									
								
							
							
						
						
									
										517
									
								
								ios-deploy.c
									
									
									
									
									
								
							| @@ -16,7 +16,7 @@ | ||||
| #include <netinet/tcp.h> | ||||
| #include "MobileDevice.h" | ||||
|  | ||||
| #define APP_VERSION    "1.3.1" | ||||
| #define APP_VERSION    "1.6.1" | ||||
| #define PREP_CMDS_PATH "/tmp/fruitstrap-lldb-prep-cmds-" | ||||
| #define LLDB_SHELL "lldb -s " PREP_CMDS_PATH | ||||
| /* | ||||
| @@ -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; | ||||
| @@ -312,87 +316,71 @@ 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"); | ||||
|  | ||||
|     if (model == NULL) { | ||||
|         return CFSTR("Unknown 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)") | ||||
|     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, "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") | ||||
|  | ||||
|     return model; | ||||
|     //return CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), hwmodel); | ||||
|     //return CFSTR("Unknown Device"); | ||||
| } | ||||
|  | ||||
| char * MYCFStringCopyUTF8String(CFStringRef aString) { | ||||
| @@ -419,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); | ||||
|  | ||||
| @@ -430,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)); | ||||
| @@ -670,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); | ||||
|  | ||||
| @@ -729,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); | ||||
| @@ -838,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)); | ||||
| @@ -863,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)); | ||||
| } | ||||
|  | ||||
| @@ -875,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 | ||||
| @@ -903,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); | ||||
| } | ||||
|  | ||||
| @@ -992,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(); | ||||
| } | ||||
|  | ||||
| @@ -1057,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 | ||||
| @@ -1080,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 | ||||
| @@ -1145,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; | ||||
| @@ -1168,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"); | ||||
| @@ -1184,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] != '/') | ||||
| @@ -1209,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); | ||||
| } | ||||
|  | ||||
| @@ -1220,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; | ||||
| } | ||||
|  | ||||
| @@ -1266,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); | ||||
| @@ -1282,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); | ||||
| @@ -1290,6 +1272,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; | ||||
| @@ -1383,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); | ||||
| @@ -1399,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); | ||||
| @@ -1419,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) { | ||||
| @@ -1434,12 +1450,73 @@ 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 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 uninstall_app(AMDeviceRef device) { | ||||
|     CFRetain(device); // don't know if this is necessary? | ||||
|  | ||||
|     printf("------ Uninstall phase ------\n"); | ||||
|  | ||||
|     //Do we already have the bundle_id passed in via the command line? if so, use it. | ||||
|     CFStringRef cf_uninstall_bundle_id = NULL; | ||||
|     if (bundle_id != NULL) | ||||
|     { | ||||
|         cf_uninstall_bundle_id = CFStringCreateWithCString(NULL, bundle_id, kCFStringEncodingASCII); | ||||
|     } else { | ||||
|         printf ("Error: you need to pass in the bundle id, (i.e. --bundle_id com.my.app)"); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     if (cf_uninstall_bundle_id == NULL) { | ||||
|         printf("Error: Unable to get bundle id from user command or package %s\n Uninstall failed\n", app_path); | ||||
|     } else { | ||||
|         AMDeviceConnect(device); | ||||
|         assert(AMDeviceIsPaired(device)); | ||||
|         assert(AMDeviceValidatePairing(device) == 0); | ||||
|         assert(AMDeviceStartSession(device) == 0); | ||||
|  | ||||
|         int code = AMDeviceSecureUninstallApplication(0, device, cf_uninstall_bundle_id, 0, NULL, 0); | ||||
|         if (code == 0) { | ||||
|             printf("[ OK ] Uninstalled package with bundle id %s\n", CFStringGetCStringPtr(cf_uninstall_bundle_id, CFStringGetSystemEncoding())); | ||||
|         } else { | ||||
|             printf("[ ERROR ] Could not uninstall package with bundle id %s\n", CFStringGetCStringPtr(cf_uninstall_bundle_id, CFStringGetSystemEncoding())); | ||||
|         } | ||||
|         assert(AMDeviceStopSession(device) == 0); | ||||
|         assert(AMDeviceDisconnect(device) == 0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void handle_device(AMDeviceRef device) { | ||||
|     //if (found_device)  | ||||
|     //if (found_device) | ||||
|     //    return; // handle one device only | ||||
|  | ||||
|     CFStringRef found_device_id = AMDeviceCopyDeviceIdentifier(device), | ||||
| @@ -1448,6 +1525,7 @@ void handle_device(AMDeviceRef device) { | ||||
|  | ||||
|     if (detect_only) { | ||||
|         printf("[....] Found %s connected through %s.\n", CFStringGetCStringPtr(device_full_name, CFStringGetSystemEncoding()), CFStringGetCStringPtr(device_interface_name, CFStringGetSystemEncoding())); | ||||
|         found_device = true; | ||||
|         return; | ||||
|     } | ||||
|     if (device_id != NULL) { | ||||
| @@ -1463,7 +1541,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); | ||||
| @@ -1471,6 +1549,14 @@ 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)); | ||||
|         } else if (strcmp("uninstall_only", command) == 0) { | ||||
|             uninstall_app(device); | ||||
|         } | ||||
|         exit(0); | ||||
|     } | ||||
| @@ -1487,20 +1573,28 @@ void handle_device(AMDeviceRef device) { | ||||
|     if (uninstall) { | ||||
|         printf("------ Uninstall phase ------\n"); | ||||
|  | ||||
|         CFStringRef bundle_id = get_bundle_id(url); | ||||
|         if (bundle_id == NULL) { | ||||
|             printf("Error: Unable to get bundle id from package %s\n Uninstall failed\n", app_path); | ||||
|         //Do we already have the bundle_id passed in via the command line? if so, use it. | ||||
|         CFStringRef cf_uninstall_bundle_id = NULL; | ||||
|         if (bundle_id != NULL) | ||||
|         { | ||||
|             cf_uninstall_bundle_id = CFStringCreateWithCString(NULL, bundle_id, kCFStringEncodingASCII); | ||||
|         } else { | ||||
|             cf_uninstall_bundle_id = get_bundle_id(url); | ||||
|         } | ||||
|  | ||||
|         if (cf_uninstall_bundle_id == NULL) { | ||||
|             printf("Error: Unable to get bundle id from user command or package %s\n Uninstall failed\n", app_path); | ||||
|         } else { | ||||
|             AMDeviceConnect(device); | ||||
|             assert(AMDeviceIsPaired(device)); | ||||
|             assert(AMDeviceValidatePairing(device) == 0); | ||||
|             assert(AMDeviceStartSession(device) == 0); | ||||
|              | ||||
|             int code = AMDeviceSecureUninstallApplication(0, device, bundle_id, 0, NULL, 0); | ||||
|  | ||||
|             int code = AMDeviceSecureUninstallApplication(0, device, cf_uninstall_bundle_id, 0, NULL, 0); | ||||
|             if (code == 0) { | ||||
|                 printf("[ OK ] Uninstalled package with bundle id %s\n", CFStringGetCStringPtr(bundle_id, CFStringGetSystemEncoding())); | ||||
|                 printf("[ OK ] Uninstalled package with bundle id %s\n", CFStringGetCStringPtr(cf_uninstall_bundle_id, CFStringGetSystemEncoding())); | ||||
|             } else { | ||||
|                 printf("[ ERROR ] Could not uninstall package with bundle id %s\n", CFStringGetCStringPtr(bundle_id, CFStringGetSystemEncoding())); | ||||
|                 printf("[ ERROR ] Could not uninstall package with bundle id %s\n", CFStringGetCStringPtr(cf_uninstall_bundle_id, CFStringGetSystemEncoding())); | ||||
|             } | ||||
|             assert(AMDeviceStopSession(device) == 0); | ||||
|             assert(AMDeviceDisconnect(device) == 0); | ||||
| @@ -1532,7 +1626,7 @@ void handle_device(AMDeviceRef device) { | ||||
|  | ||||
|         close(afcFd); | ||||
|  | ||||
|          | ||||
|  | ||||
|  | ||||
|         AMDeviceConnect(device); | ||||
|         assert(AMDeviceIsPaired(device)); | ||||
| @@ -1568,9 +1662,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 | ||||
| @@ -1583,7 +1677,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: | ||||
| @@ -1609,10 +1703,12 @@ void timeout_callback(CFRunLoopTimerRef timer, void *info) { | ||||
|     { | ||||
|       if (!debug) { | ||||
|           printf("[....] No more devices found.\n"); | ||||
|           exit(exitcode_error); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|  | ||||
|       if (detect_only && !found_device) { | ||||
|           exit(exitcode_error); | ||||
|           return; | ||||
|       } else { | ||||
|           int mypid = getpid(); | ||||
|           if ((parent != 0) && (parent == mypid) && (child != 0)) | ||||
|           { | ||||
| @@ -1630,7 +1726,7 @@ void timeout_callback(CFRunLoopTimerRef timer, void *info) { | ||||
| void usage(const char* app) { | ||||
|     printf( | ||||
|         "Usage: %s [OPTION]...\n" | ||||
|         "  -d, --debug                  launch the app in GDB after installation\n" | ||||
|         "  -d, --debug                  launch the app in lldb after installation\n" | ||||
|         "  -i, --id <device_id>         the id of the device to connect to\n" | ||||
|         "  -c, --detect                 only detect if the device is connected\n" | ||||
|         "  -b, --bundle <bundle.app>    the path to the app bundle to be installed\n" | ||||
| @@ -1642,14 +1738,18 @@ 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 <number>          port used for device, default: 12345 \n" | ||||
|         "  -p, --port <number>          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" | ||||
|         "  -9, --uninstall_only         uninstall the app ONLY. Use only with -1 <bundle_id> \n" | ||||
|         "  -1, --bundle_id <bundle id>  specify bundle id for list and upload\n" | ||||
|         "  -l, --list                   list files\n" | ||||
|         "  -o, --upload <file>          upload file\n" | ||||
|         "  -w, --download               download app tree\n" | ||||
|         "  -2, --to <target pathname>   use together with up/download file/tree. specify target\n" | ||||
|         "  -V, --version                print the executable version \n", | ||||
|         "  -D, --mkdir <dir>            make directory on device\n" | ||||
|         "  -R, --rm <path>              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); | ||||
| } | ||||
|  | ||||
| @@ -1674,16 +1774,20 @@ int main(int argc, char *argv[]) { | ||||
|         { "noinstall", no_argument, NULL, 'm' }, | ||||
|         { "port", required_argument, NULL, 'p' }, | ||||
|         { "uninstall", no_argument, NULL, 'r' }, | ||||
|         { "uninstall_only", no_argument, NULL, '9'}, | ||||
|         { "list", optional_argument, NULL, 'l' }, | ||||
|         { "bundle_id", required_argument, NULL, '1'}, | ||||
|         { "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 }, | ||||
|     }; | ||||
|     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, "VmcdvunrILeD:R:i:b:a:t:g:x:p:1:2:o:l::w::9::", longopts, NULL)) != -1) | ||||
|     { | ||||
|         switch (ch) { | ||||
|         case 'm': | ||||
| @@ -1723,16 +1827,21 @@ int main(int argc, char *argv[]) { | ||||
|             break; | ||||
|         case 'c': | ||||
|             detect_only = true; | ||||
|             debug = 1; | ||||
|             break; | ||||
|         case 'V': | ||||
|             show_version(); | ||||
|             return exitcode_error; | ||||
|             return 0; | ||||
|         case 'p': | ||||
|             port = atoi(optarg); | ||||
|             break; | ||||
|         case 'r': | ||||
|             uninstall = 1; | ||||
|             break; | ||||
|         case '9': | ||||
|             command_only = true; | ||||
|             command = "uninstall_only"; | ||||
|             break; | ||||
|         case '1': | ||||
|             bundle_id = optarg; | ||||
|             break; | ||||
| @@ -1754,6 +1863,20 @@ 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"; | ||||
|             break; | ||||
|         default: | ||||
|             usage(argv[0]); | ||||
|             return exitcode_error; | ||||
| @@ -1762,6 +1885,7 @@ int main(int argc, char *argv[]) { | ||||
|  | ||||
|     if (!app_path && !detect_only && !command_only) { | ||||
|         usage(argv[0]); | ||||
|         printf ("ERROR: One of -[b|c|o|l|w|D|R|e|9] is required to proceed!\n"); | ||||
|         exit(exitcode_error); | ||||
|     } | ||||
|  | ||||
| @@ -1794,4 +1918,3 @@ int main(int argc, char *argv[]) { | ||||
|     AMDeviceNotificationSubscribe(&device_callback, 0, 0, NULL, ¬ify); | ||||
|     CFRunLoopRun(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| { | ||||
|   "name": "ios-deploy", | ||||
|   "version": "1.3.1", | ||||
|   "version": "1.6.1", | ||||
|   "os" : [ "darwin" ], | ||||
|   "description": "launch iOS apps iOS devices from the command line (Xcode 6)", | ||||
|   "main": "ios-deploy", | ||||
|   "scripts": { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user