├── src ├── ios-deploy │ ├── version.h │ ├── device_db.h │ ├── MobileDevice.h │ ├── errors.h │ └── ios-deploy.m ├── ios-deploy-lib │ ├── libios_deploy.m │ └── libios_deploy.h ├── ios-deploy-tests │ ├── Info.plist │ └── ios_deploy_tests.m └── scripts │ ├── check_reqs.js │ └── lldb.py ├── demo ├── .gitignore ├── demo.c ├── Entitlements.plist ├── ResourceRules.plist ├── Makefile └── Info.plist ├── .gitignore ├── .travis.yml ├── LICENSE ├── .github ├── ISSUE_TEMPLATE.md └── CONTRIBUTING.md ├── package.json ├── ios-deploy.xcodeproj ├── xcshareddata │ └── xcschemes │ │ └── ios-deploy-tests.xcscheme └── project.pbxproj └── README.md /src/ios-deploy/version.h: -------------------------------------------------------------------------------- 1 | "2.0.0" -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | demo 2 | demo.app 3 | demo.dSYM 4 | /.DS_Store 5 | *~ 6 | -------------------------------------------------------------------------------- /src/ios-deploy-lib/libios_deploy.m: -------------------------------------------------------------------------------- 1 | #import "libios_deploy.h" 2 | 3 | @implementation ios_deploy_lib 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /src/ios-deploy-lib/libios_deploy.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface ios_deploy_lib : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | node_modules/* 3 | _Frameworks/* 4 | /.DS_Store 5 | *~ 6 | src/scripts/lldb.pyc 7 | src/ios-deploy/lldb.py.h 8 | -------------------------------------------------------------------------------- /demo/demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, const char* argv[]) { 4 | int i; 5 | for (i = 0; i < argc; i++) { 6 | printf("argv[%d] = %s\n", i, argv[i]); 7 | } 8 | return 0; 9 | } -------------------------------------------------------------------------------- /demo/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | get-task-allow 6 | 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | sudo: false 3 | install: 4 | - npm install 5 | script: 6 | - npm test 7 | notifications: 8 | slack: 9 | secure: ZJtWH/UQ+AdzakirR0gg7EL1SJg2hd+HWJPk/Gn5fibFh05P7qYdFu056fjQyVM2Kbv+39bnv+fg4lxb3OeewSDCSYgbJ7JzYFSwCb/ERwtJgoUJIDZiNzsTodJ4mCFnddgA0DEIFPhK2ntNa71VnKrVbWDJTY4+Kl+GBtmPplk= 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ios-deploy is available under the provisions of the GNU General Public License, 2 | version 3 (or later), available here: http://www.gnu.org/licenses/gpl-3.0.html 3 | 4 | 5 | Error codes used for error messages were taken from SDMMobileDevice framework, 6 | originally reverse engineered by Sam Marshall. SDMMobileDevice is distributed 7 | under BSD 3-Clause license and is available here: 8 | https://github.com/samdmarshall/SDMMobileDevice 9 | -------------------------------------------------------------------------------- /demo/ResourceRules.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | rules 6 | 7 | .* 8 | 9 | Info.plist 10 | 11 | omit 12 | 13 | weight 14 | 10 15 | 16 | ResourceRules.plist 17 | 18 | omit 19 | 20 | weight 21 | 100 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /demo/Makefile: -------------------------------------------------------------------------------- 1 | IOS_SDK_VERSION = 9.1 2 | 3 | IOS_CC = gcc -ObjC 4 | IOS_SDK = $(shell xcode-select --print-path)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$(IOS_SDK_VERSION).sdk 5 | 6 | all: clean demo.app 7 | 8 | demo.app: demo Info.plist 9 | mkdir -p demo.app 10 | cp demo demo.app/ 11 | cp Info.plist ResourceRules.plist demo.app/ 12 | codesign -f -s "iPhone Developer" --entitlements Entitlements.plist demo.app 13 | 14 | demo: demo.c 15 | $(IOS_CC) -g -arch armv7 -isysroot $(IOS_SDK) -framework CoreFoundation -o demo demo.c 16 | 17 | debug: all ios-deploy 18 | @../build/Release/ios-deploy --debug --bundle demo.app 19 | 20 | clean: 21 | @rm -rf *.app demo demo.dSYM 22 | 23 | ios-deploy: 24 | @xcodebuild -project ../ios-deploy.xcodeproj 25 | -------------------------------------------------------------------------------- /demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | demo 7 | CFBundleSupportedPlatforms 8 | 9 | iPhoneOS 10 | 11 | CFBundleExecutable 12 | demo 13 | CFBundleVersion 14 | 1.0 15 | CFBundleIdentifier 16 | demo 17 | CFBundleResourceSpecification 18 | ResourceRules.plist 19 | LSRequiresIPhoneOS 20 | 21 | CFBundleDisplayName 22 | demo 23 | 24 | -------------------------------------------------------------------------------- /src/ios-deploy-tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## MUST READ BEFORE YOU FILE (DELETE THIS SECTION BEFORE FILING) 2 | 3 | Include the **command line arguments** you used for ios-deploy. 4 | 5 | Don't forget to check out the [El Capitan](https://github.com/phonegap/ios-deploy/blob/master/README.md#os-x-1011-el-capitan) section of the [README](https://github.com/phonegap/ios-deploy/blob/master/README.md) before filing this issue. 6 | 7 | # Expected behavior 8 | 9 | 10 | # Actual behavior. 11 | 12 | 13 | # Steps to reproduce the problem 14 | 15 | 16 | # System Specs 17 | 18 | Please run the commands below in your Terminal.app and include it in the issue. Check when done and include results below. 19 | 20 | - [ ] 1. system_profiler SPSoftwareDataType 21 | - [ ] 2. ios-deploy -V 22 | - [ ] 3. xcodebuild -version 23 | - [ ] 4. xcode-select --print-path 24 | - [ ] 5. gcc --version 25 | - [ ] 6. lldb --version 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/ios-deploy-tests/ios_deploy_tests.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface ios_deploy_tests : XCTestCase 4 | 5 | @end 6 | 7 | @implementation ios_deploy_tests 8 | 9 | - (void)setUp { 10 | [super setUp]; 11 | // Put setup code here. This method is called before the invocation of each test method in the class. 12 | } 13 | 14 | - (void)tearDown { 15 | // Put teardown code here. This method is called after the invocation of each test method in the class. 16 | [super tearDown]; 17 | } 18 | 19 | - (void)testExample { 20 | // This is an example of a functional test case. 21 | // Use XCTAssert and related functions to verify your tests produce the correct results. 22 | } 23 | 24 | - (void)testPerformanceExample { 25 | // This is an example of a performance test case. 26 | [self measureBlock:^{ 27 | // Put the code you want to measure the time of here. 28 | }]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ios-deploy", 3 | "version": "2.0.0", 4 | "os": [ 5 | "darwin" 6 | ], 7 | "description": "launch iOS apps iOS devices from the command line (Xcode 7)", 8 | "main": "ios-deploy", 9 | "scripts": { 10 | }, 11 | "bin": "./build/Release/ios-deploy", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/phonegap/ios-deploy" 15 | }, 16 | "devDependencies": { 17 | "jshint": "2.5.8" 18 | }, 19 | "scripts": { 20 | "preinstall": "./src/scripts/check_reqs.js && xcodebuild", 21 | "test": "npm run pycompile && npm run jshint && xcodebuild -target ios-deploy-lib && xcodebuild test -scheme ios-deploy-tests", 22 | "jshint": "node node_modules/jshint/bin/jshint src/scripts/*.js", 23 | "pycompile": "python -m py_compile src/scripts/*.py" 24 | }, 25 | "keywords": [ 26 | "ios-deploy", 27 | "deploy to iOS device" 28 | ], 29 | "bugs": { 30 | "url": "https://github.com/phonegap/ios-deploy/issues" 31 | }, 32 | "author": "Greg Hughes", 33 | "license": "GPLv3" 34 | } 35 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to ios-deploy 2 | 3 | Github url: 4 | 5 | https://github.com/phonegap/ios-deploy 6 | 7 | Git clone url: 8 | 9 | https://github.com/phonegap/ios-deploy.git 10 | 11 | ## Filing an issue 12 | 13 | Please run the commands below in your Terminal.app and include it in the issue: 14 | 15 | ``` 16 | 1. sw_vers -productVersion 17 | 2. ios-deploy -V 18 | 3. xcodebuild -version 19 | 4. xcode-select --print-path 20 | 5. gcc --version 21 | 6. lldb --version 22 | 23 | ``` 24 | Also include **command line arguments** you used for ios-deploy. 25 | 26 | Don't forget to check out the [El Capitan](https://github.com/phonegap/ios-deploy/blob/master/README.md#os-x-1011-el-capitan) section of the [README](https://github.com/phonegap/ios-deploy/blob/master/README.md) before filing that issue! 27 | 28 | 29 | ## Sending a Pull Request 30 | 31 | Please **create a topic branch** for your issue before submitting your pull request. You will be asked to re-submit if your pull request contains unrelated commits. 32 | 33 | Please elaborate regarding the problem the pull request is supposed to solve, and perhaps also link to any relevant issues the pull request is trying to fix. -------------------------------------------------------------------------------- /src/scripts/check_reqs.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var util = require('util'); 4 | var os = require('os'); 5 | var child_process = require('child_process'); 6 | 7 | var XCODEBUILD_MIN_VERSION = '7.0'; 8 | var XCODEBUILD_NOT_FOUND_MESSAGE = util.format('Please install Xcode version %s or greater from the Mac App Store.', XCODEBUILD_MIN_VERSION); 9 | var TOOL = 'xcodebuild'; 10 | 11 | var xcode_version = child_process.spawn(TOOL, ['-version']), 12 | version_string = ''; 13 | 14 | xcode_version.stdout.on('data', function (data) { 15 | version_string += data; 16 | }); 17 | 18 | xcode_version.stderr.on('data', function (data) { 19 | console.log('stderr: ' + data); 20 | }); 21 | 22 | xcode_version.on('error', function (err) { 23 | console.log(util.format('Tool %s was not found. %s', TOOL, XCODEBUILD_NOT_FOUND_MESSAGE)); 24 | }); 25 | 26 | xcode_version.on('close', function (code) { 27 | if (code === 0) { 28 | var arr = version_string.match(/^Xcode (\d+\.\d+)/); 29 | var ver = arr[1]; 30 | 31 | if (os.release() >= '15.0.0' && ver < '7.0') { 32 | console.log(util.format('You need at least Xcode 7.0 when you are on OS X 10.11 El Capitan (you have version %s)', ver)); 33 | process.exit(1); 34 | } 35 | 36 | if (ver < XCODEBUILD_MIN_VERSION) { 37 | console.log(util.format('%s : %s. (you have version %s)', TOOL, XCODEBUILD_NOT_FOUND_MESSAGE, ver)); 38 | } 39 | 40 | if (os.release() >= '15.0.0') { // print the El Capitan warning 41 | console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'); 42 | console.log('!!!! WARNING: You are on OS X 10.11 El Capitan or greater, you may need to add the'); 43 | console.log('!!!! WARNING: `--unsafe-perm=true` flag when running `npm install`'); 44 | console.log('!!!! WARNING: or else it will fail.'); 45 | console.log('!!!! WARNING: link:'); 46 | console.log('!!!! WARNING: https://github.com/phonegap/ios-deploy#os-x-1011-el-capitan'); 47 | console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'); 48 | } 49 | 50 | } 51 | process.exit(code); 52 | }); 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /ios-deploy.xcodeproj/xcshareddata/xcschemes/ios-deploy-tests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 48 | 49 | 51 | 52 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/scripts/lldb.py: -------------------------------------------------------------------------------- 1 | import time 2 | import os 3 | import sys 4 | import shlex 5 | import lldb 6 | 7 | listener = None 8 | 9 | def connect_command(debugger, command, result, internal_dict): 10 | # These two are passed in by the script which loads us 11 | connect_url = internal_dict['fruitstrap_connect_url'] 12 | error = lldb.SBError() 13 | 14 | # We create a new listener here and will use it for both target and the process. 15 | # It allows us to prevent data races when both our code and internal lldb code 16 | # try to process STDOUT/STDERR messages 17 | global listener 18 | listener = lldb.SBListener('iosdeploy_listener') 19 | 20 | listener.StartListeningForEventClass(debugger, 21 | lldb.SBTarget.GetBroadcasterClassName(), 22 | lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR) 23 | 24 | process = lldb.target.ConnectRemote(listener, connect_url, None, error) 25 | 26 | # Wait for connection to succeed 27 | events = [] 28 | state = (process.GetState() or lldb.eStateInvalid) 29 | while state != lldb.eStateConnected: 30 | event = lldb.SBEvent() 31 | if listener.WaitForEvent(1, event): 32 | state = process.GetStateFromEvent(event) 33 | events.append(event) 34 | else: 35 | state = lldb.eStateInvalid 36 | 37 | # Add events back to queue, otherwise lldb freezes 38 | for event in events: 39 | listener.AddEvent(event) 40 | 41 | def run_command(debugger, command, result, internal_dict): 42 | device_app = internal_dict['fruitstrap_device_app'] 43 | args = command.split('--',1) 44 | error = lldb.SBError() 45 | lldb.target.modules[0].SetPlatformFileSpec(lldb.SBFileSpec(device_app)) 46 | args_arr = [] 47 | if len(args) > 1: 48 | args_arr = shlex.split(args[1]) 49 | args_arr = args_arr + shlex.split('{args}') 50 | 51 | launchInfo = lldb.SBLaunchInfo(args_arr) 52 | global listener 53 | launchInfo.SetListener(listener) 54 | 55 | #This env variable makes NSLog, CFLog and os_log messages get mirrored to stderr 56 | #https://stackoverflow.com/a/39581193 57 | launchInfo.SetEnvironmentEntries(['OS_ACTIVITY_DT_MODE=enable'], True) 58 | 59 | lldb.target.Launch(launchInfo, error) 60 | lockedstr = ': Locked' 61 | if lockedstr in str(error): 62 | print('\\nDevice Locked\\n') 63 | os._exit(254) 64 | else: 65 | print(str(error)) 66 | 67 | def safequit_command(debugger, command, result, internal_dict): 68 | process = lldb.target.process 69 | state = process.GetState() 70 | if state == lldb.eStateRunning: 71 | process.Detach() 72 | os._exit(0) 73 | elif state > lldb.eStateRunning: 74 | os._exit(state) 75 | else: 76 | print('\\nApplication has not been launched\\n') 77 | os._exit(1) 78 | 79 | def autoexit_command(debugger, command, result, internal_dict): 80 | global listener 81 | process = lldb.target.process 82 | 83 | detectDeadlockTimeout = {detect_deadlock_timeout} 84 | printBacktraceTime = time.time() + detectDeadlockTimeout if detectDeadlockTimeout > 0 else None 85 | 86 | # This line prevents internal lldb listener from processing STDOUT/STDERR messages. Without it, an order of log writes is incorrect sometimes 87 | debugger.GetListener().StopListeningForEvents(process.GetBroadcaster(), lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR ) 88 | 89 | event = lldb.SBEvent() 90 | 91 | def ProcessSTDOUT(): 92 | stdout = process.GetSTDOUT(1024) 93 | while stdout: 94 | sys.stdout.write(stdout) 95 | stdout = process.GetSTDOUT(1024) 96 | 97 | def ProcessSTDERR(): 98 | stderr = process.GetSTDERR(1024) 99 | while stderr: 100 | sys.stdout.write(stderr) 101 | stderr = process.GetSTDERR(1024) 102 | 103 | while True: 104 | if listener.WaitForEvent(1, event) and lldb.SBProcess.EventIsProcessEvent(event): 105 | state = lldb.SBProcess.GetStateFromEvent(event) 106 | type = event.GetType() 107 | 108 | if type & lldb.SBProcess.eBroadcastBitSTDOUT: 109 | ProcessSTDOUT() 110 | 111 | if type & lldb.SBProcess.eBroadcastBitSTDERR: 112 | ProcessSTDERR() 113 | 114 | else: 115 | state = process.GetState() 116 | 117 | if state != lldb.eStateRunning: 118 | # Let's make sure that we drained our streams before exit 119 | ProcessSTDOUT() 120 | ProcessSTDERR() 121 | 122 | if state == lldb.eStateExited: 123 | sys.stdout.write( '\\nPROCESS_EXITED\\n' ) 124 | os._exit(process.GetExitStatus()) 125 | elif printBacktraceTime is None and state == lldb.eStateStopped: 126 | sys.stdout.write( '\\nPROCESS_STOPPED\\n' ) 127 | debugger.HandleCommand('bt') 128 | os._exit({exitcode_app_crash}) 129 | elif state == lldb.eStateCrashed: 130 | sys.stdout.write( '\\nPROCESS_CRASHED\\n' ) 131 | debugger.HandleCommand('bt') 132 | os._exit({exitcode_app_crash}) 133 | elif state == lldb.eStateDetached: 134 | sys.stdout.write( '\\nPROCESS_DETACHED\\n' ) 135 | os._exit({exitcode_app_crash}) 136 | elif printBacktraceTime is not None and time.time() >= printBacktraceTime: 137 | printBacktraceTime = None 138 | sys.stdout.write( '\\nPRINT_BACKTRACE_TIMEOUT\\n' ) 139 | debugger.HandleCommand('process interrupt') 140 | debugger.HandleCommand('bt all') 141 | debugger.HandleCommand('continue') 142 | printBacktraceTime = time.time() + 5 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/phonegap/ios-deploy.svg?branch=master)](https://travis-ci.org/phonegap/ios-deploy) 2 | 3 | ios-deploy 4 | ========== 5 | Install and debug iOS apps without using Xcode. Designed to work on un-jailbroken devices. 6 | 7 | ## Requirements 8 | 9 | * Mac OS X. Tested on 10.11 El Capitan, 10.12 Sierra, iOS 9.0 and iOS 10.0 10 | * You need to have a valid iOS Development certificate installed. 11 | * Xcode 7 or greater should be installed (**NOT** Command Line Tools!) 12 | 13 | ## Roadmap 14 | 15 | See our [milestones](https://github.com/phonegap/ios-deploy/milestones). 16 | 17 | Significant changes: 18 | 19 | 1.8.0 will use an Xcode project instead of a Makefile (to prepare for 2.0.0) (1.x branch) 20 | 2.0.0 will break out the commands into their own files, and create ios-deploy-lib for node.js use (master branch) 21 | 22 | ## Development 23 | 24 | The legacy `1.x` version is under the `1.x` branch. Bug fixes for the `1.x` series will occur under there. 25 | The 'master' branch now contains the `2.x` series, and is the development branch. 26 | 27 | ## Installation 28 | ======= 29 | 30 | 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): 31 | 32 | ``` 33 | brew install node 34 | ``` 35 | 36 | Now install ios-deploy with the [node.js](https://nodejs.org) package manager: 37 | 38 | ``` 39 | npm install -g ios-deploy 40 | ``` 41 | 42 | To build from source: 43 | 44 | ``` 45 | xcodebuild 46 | ``` 47 | 48 | This will build `ios-deploy` into the `build/Release` folder. 49 | 50 | ## Testing 51 | 52 | Run: 53 | 54 | ``` 55 | npm install && npm test 56 | ``` 57 | 58 | ### OS X 10.11 El Capitan or greater 59 | 60 | If you are *not* using a node version manager like [nvm](https://github.com/creationix/nvm) or [n](https://github.com/tj/n), you may have to do either of these three things below when under El Capitan: 61 | 62 | 1. Add the `--unsafe-perm=true` flag when installing ios-deploy 63 | 2. Add the `--allow-root` flag when installing ios-deploy 64 | 3. Ensure the `nobody` user has write access to `/usr/local/lib/node_modules/ios-deploy/ios-deploy` 65 | 66 | ## Usage 67 | 68 | Usage: ios-deploy [OPTION]... 69 | -d, --debug launch the app in lldb after installation 70 | -i, --id the id of the device to connect to 71 | -c, --detect only detect if the device is connected 72 | -b, --bundle the path to the app bundle to be installed 73 | -a, --args command line arguments to pass to the app when launching it 74 | -t, --timeout number of seconds to wait for a device to be connected 75 | -u, --unbuffered don't buffer stdout 76 | -n, --nostart do not start the app when debugging 77 | -I, --noninteractive start in non interactive mode (quit when app crashes or exits) 78 | -L, --justlaunch just launch the app and exit lldb 79 | -v, --verbose enable verbose output 80 | -m, --noinstall directly start debugging without app install (-d not required) 81 | -p, --port port used for device, default: dynamic 82 | -r, --uninstall uninstall the app before install (do not use with -m; app cache and data are cleared) 83 | -9, --uninstall_only uninstall the app ONLY. Use only with -1 84 | -1, --bundle_id specify bundle id for list and upload 85 | -l, --list list files 86 | -o, --upload upload file 87 | -w, --download download app tree 88 | -2, --to use together with up/download file/tree. specify target 89 | -D, --mkdir make directory on device 90 | -R, --rm remove file or directory on device (directories must be empty) 91 | -V, --version print the executable version 92 | -e, --exists check if the app with given bundle_id is installed or not 93 | -B, --list_bundle_id list bundle_id 94 | -W, --no-wifi ignore wifi devices 95 | --detect_deadlocks start printing backtraces for all threads periodically after specific amount of seconds 96 | 97 | ## Examples 98 | 99 | The commands below assume that you have an app called `my.app` with bundle id `bundle.id`. Substitute where necessary. 100 | 101 | // deploy and debug your app to a connected device 102 | ios-deploy --debug --bundle my.app 103 | 104 | // deploy and debug your app to a connected device, skipping any wi-fi connection (use USB) 105 | ios-deploy --debug --bundle my.app --no-wifi 106 | 107 | // deploy and launch your app to a connected device, but quit the debugger after 108 | ios-deploy --justlaunch --debug --bundle my.app 109 | 110 | // deploy and launch your app to a connected device, quit when app crashes or exits 111 | ios-deploy --noninteractive --debug --bundle my.app 112 | 113 | // Upload a file to your app's Documents folder 114 | ios-deploy --bundle_id 'bundle.id' --upload test.txt --to Documents/test.txt 115 | 116 | // Download your app's Documents, Library and tmp folders 117 | ios-deploy --bundle_id 'bundle.id' --download --to MyDestinationFolder 118 | 119 | // List the contents of your app's Documents, Library and tmp folders 120 | ios-deploy --bundle_id 'bundle.id' --list 121 | 122 | // deploy and debug your app to a connected device, uninstall the app first 123 | ios-deploy --uninstall --debug --bundle my.app 124 | 125 | // check whether an app by bundle id exists on the device (check return code `echo $?`) 126 | ios-deploy --exists --bundle_id com.apple.mobilemail 127 | 128 | // Download the Documents directory of the app *only* 129 | ios-deploy --download=/Documents --bundle_id my.app.id --to ./my_download_location 130 | 131 | // List ids and names of connected devices 132 | ios-deploy -c 133 | 134 | // Uninstall an app 135 | ios-deploy --uninstall_only --bundle_id my.bundle.id 136 | 137 | // list all bundle ids of all apps on your device 138 | ios-deploy --list_bundle_id 139 | 140 | ## Demo 141 | 142 | The included demo.app represents the minimum required to get code running on iOS. 143 | 144 | * `make demo.app` will generate the demo.app executable. If it doesn't compile, modify `IOS_SDK_VERSION` in the Makefile. 145 | * `make debug` will install demo.app and launch a LLDB session. 146 | 147 | ## Notes 148 | * `--detect_deadlocks` can help to identify an exact state of application's threads in case of a deadlock. It works like this: The user specifies the amount of time ios-deploy runs the app as usual. When the timeout is elapsed ios-deploy starts to print call-stacks of all threads every 5 seconds and the app keeps running. Comparing threads' call-stacks between each other helps to identify the threads which were stuck. 149 | -------------------------------------------------------------------------------- /src/ios-deploy/device_db.h: -------------------------------------------------------------------------------- 1 | // 2 | // devices.h 3 | // ios-deploy 4 | // 5 | // Created by Gusts Kaksis on 26/10/2016. 6 | // Copyright © 2016 PhoneGap. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define ADD_DEVICE(model, name, sdk, arch) {CFSTR(model), CFSTR(name), CFSTR(sdk), CFSTR(arch)} 12 | 13 | typedef struct { 14 | CFStringRef model; 15 | CFStringRef name; 16 | CFStringRef sdk; 17 | CFStringRef arch; 18 | } device_desc; 19 | 20 | #define UNKNOWN_DEVICE_IDX 0 21 | 22 | device_desc device_db[] = { 23 | ADD_DEVICE("UNKN", "Unknown Device", "uknownos", "unkarch"), 24 | 25 | // iPod Touch 26 | 27 | ADD_DEVICE("N45AP", "iPod Touch", "iphoneos", "armv7"), 28 | ADD_DEVICE("N72AP", "iPod Touch 2G", "iphoneos", "armv7"), 29 | ADD_DEVICE("N18AP", "iPod Touch 3G", "iphoneos", "armv7"), 30 | ADD_DEVICE("N81AP", "iPod Touch 4G", "iphoneos", "armv7"), 31 | ADD_DEVICE("N78AP", "iPod Touch 5G", "iphoneos", "armv7"), 32 | ADD_DEVICE("N78AAP", "iPod Touch 5G", "iphoneos", "armv7"), 33 | ADD_DEVICE("N102AP", "iPod Touch 6G", "iphoneos", "arm64"), 34 | 35 | // iPad 36 | 37 | ADD_DEVICE("K48AP", "iPad", "iphoneos", "armv7"), 38 | ADD_DEVICE("K93AP", "iPad 2", "iphoneos", "armv7"), 39 | ADD_DEVICE("K94AP", "iPad 2 (GSM)", "iphoneos", "armv7"), 40 | ADD_DEVICE("K95AP", "iPad 2 (CDMA)", "iphoneos", "armv7"), 41 | ADD_DEVICE("K93AAP", "iPad 2 (Wi-Fi, revision A)", "iphoneos", "armv7"), 42 | ADD_DEVICE("J1AP", "iPad 3", "iphoneos", "armv7"), 43 | ADD_DEVICE("J2AP", "iPad 3 (GSM)", "iphoneos", "armv7"), 44 | ADD_DEVICE("J2AAP", "iPad 3 (CDMA)", "iphoneos", "armv7"), 45 | ADD_DEVICE("P101AP", "iPad 4", "iphoneos", "armv7s"), 46 | ADD_DEVICE("P102AP", "iPad 4 (GSM)", "iphoneos", "armv7s"), 47 | ADD_DEVICE("P103AP", "iPad 4 (CDMA)", "iphoneos", "armv7s"), 48 | ADD_DEVICE("J71AP", "iPad Air", "iphoneos", "arm64"), 49 | ADD_DEVICE("J72AP", "iPad Air (GSM)", "iphoneos", "arm64"), 50 | ADD_DEVICE("J73AP", "iPad Air (CDMA)", "iphoneos", "arm64"), 51 | ADD_DEVICE("J81AP", "iPad Air 2", "iphoneos", "arm64"), 52 | ADD_DEVICE("J82AP", "iPad Air 2 (GSM)", "iphoneos", "arm64"), 53 | ADD_DEVICE("J83AP", "iPad Air 2 (CDMA)", "iphoneos", "arm64"), 54 | ADD_DEVICE("J71sAP", "iPad (2017)", "iphoneos", "arm64"), 55 | ADD_DEVICE("J71tAP", "iPad (2017)", "iphoneos", "arm64"), 56 | ADD_DEVICE("J72sAP", "iPad (2017)", "iphoneos", "arm64"), 57 | ADD_DEVICE("J72tAP", "iPad (2017)", "iphoneos", "arm64"), 58 | 59 | // iPad Pro 60 | 61 | ADD_DEVICE("J98aAP", "iPad Pro (12.9\")", "iphoneos", "arm64"), 62 | ADD_DEVICE("J99aAP", "iPad Pro (12.9\")", "iphoneos", "arm64"), 63 | ADD_DEVICE("J120AP", "iPad Pro 2G (12.9\")", "iphoneos", "arm64"), 64 | ADD_DEVICE("J121AP", "iPad Pro 2G (12.9\")", "iphoneos", "arm64"), 65 | ADD_DEVICE("J127AP", "iPad Pro (9.7\")", "iphoneos", "arm64"), 66 | ADD_DEVICE("J128AP", "iPad Pro (9.7\")", "iphoneos", "arm64"), 67 | ADD_DEVICE("J207AP", "iPad Pro (10.5\")", "iphoneos", "arm64"), 68 | ADD_DEVICE("J208AP", "iPad Pro (10.5\")", "iphoneos", "arm64"), 69 | 70 | // iPad Mini 71 | 72 | ADD_DEVICE("P105AP", "iPad mini", "iphoneos", "armv7"), 73 | ADD_DEVICE("P106AP", "iPad mini (GSM)", "iphoneos", "armv7"), 74 | ADD_DEVICE("P107AP", "iPad mini (CDMA)", "iphoneos", "armv7"), 75 | ADD_DEVICE("J85AP", "iPad mini 2", "iphoneos", "arm64"), 76 | ADD_DEVICE("J86AP", "iPad mini 2 (GSM)", "iphoneos", "arm64"), 77 | ADD_DEVICE("J87AP", "iPad mini 2 (CDMA)", "iphoneos", "arm64"), 78 | ADD_DEVICE("J85MAP", "iPad mini 3", "iphoneos", "arm64"), 79 | ADD_DEVICE("J86MAP", "iPad mini 3 (GSM)", "iphoneos", "arm64"), 80 | ADD_DEVICE("J87MAP", "iPad mini 3 (CDMA)", "iphoneos", "arm64"), 81 | ADD_DEVICE("J96AP", "iPad mini 4", "iphoneos", "arm64"), 82 | ADD_DEVICE("J97AP", "iPad mini 4 (GSM)", "iphoneos", "arm64"), 83 | 84 | // iPhone 85 | 86 | ADD_DEVICE("M68AP", "iPhone", "iphoneos", "armv7"), 87 | ADD_DEVICE("N82AP", "iPhone 3G", "iphoneos", "armv7"), 88 | ADD_DEVICE("N88AP", "iPhone 3GS", "iphoneos", "armv7"), 89 | ADD_DEVICE("N90AP", "iPhone 4 (GSM)", "iphoneos", "armv7"), 90 | ADD_DEVICE("N92AP", "iPhone 4 (CDMA)", "iphoneos", "armv7"), 91 | ADD_DEVICE("N90BAP", "iPhone 4 (GSM, revision A)", "iphoneos", "armv7"), 92 | ADD_DEVICE("N94AP", "iPhone 4S", "iphoneos", "armv7"), 93 | ADD_DEVICE("N41AP", "iPhone 5 (GSM)", "iphoneos", "armv7s"), 94 | ADD_DEVICE("N42AP", "iPhone 5 (Global/CDMA)", "iphoneos", "armv7s"), 95 | ADD_DEVICE("N48AP", "iPhone 5c (GSM)", "iphoneos", "armv7s"), 96 | ADD_DEVICE("N49AP", "iPhone 5c (Global/CDMA)", "iphoneos", "armv7s"), 97 | ADD_DEVICE("N51AP", "iPhone 5s (GSM)", "iphoneos", "arm64"), 98 | ADD_DEVICE("N53AP", "iPhone 5s (Global/CDMA)", "iphoneos", "arm64"), 99 | ADD_DEVICE("N61AP", "iPhone 6 (GSM)", "iphoneos", "arm64"), 100 | ADD_DEVICE("N56AP", "iPhone 6 Plus", "iphoneos", "arm64"), 101 | ADD_DEVICE("N71mAP", "iPhone 6s", "iphoneos", "arm64"), 102 | ADD_DEVICE("N71AP", "iPhone 6s", "iphoneos", "arm64"), 103 | ADD_DEVICE("N66AP", "iPhone 6s Plus", "iphoneos", "arm64"), 104 | ADD_DEVICE("N66mAP", "iPhone 6s Plus", "iphoneos", "arm64"), 105 | ADD_DEVICE("N69AP", "iPhone SE", "iphoneos", "arm64"), 106 | ADD_DEVICE("N69uAP", "iPhone SE", "iphoneos", "arm64"), 107 | ADD_DEVICE("D10AP", "iPhone 7", "iphoneos", "arm64"), 108 | ADD_DEVICE("D101AP", "iPhone 7", "iphoneos", "arm64"), 109 | ADD_DEVICE("D11AP", "iPhone 7 Plus", "iphoneos", "arm64"), 110 | ADD_DEVICE("D111AP", "iPhone 7 Plus", "iphoneos", "arm64"), 111 | 112 | // Apple TV 113 | 114 | ADD_DEVICE("K66AP", "Apple TV 2G", "appletvos", "armv7"), 115 | ADD_DEVICE("J33AP", "Apple TV 3G", "appletvos", "armv7"), 116 | ADD_DEVICE("J33IAP", "Apple TV 3.1G", "appletvos", "armv7"), 117 | ADD_DEVICE("J42dAP", "Apple TV 4G", "appletvos", "arm64"), 118 | }; 119 | -------------------------------------------------------------------------------- /src/ios-deploy/MobileDevice.h: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------------- 2 | * MobileDevice.h - interface to MobileDevice.framework 3 | * $LastChangedDate: 2007-07-09 18:59:29 -0700 (Mon, 09 Jul 2007) $ 4 | * 5 | * Copied from http://iphonesvn.halifrag.com/svn/iPhone/ 6 | * With modifications from Allen Porter and Scott Turner 7 | * 8 | * ------------------------------------------------------------------------- */ 9 | 10 | #ifndef MOBILEDEVICE_H 11 | #define MOBILEDEVICE_H 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | #if defined(WIN32) 18 | #include 19 | typedef unsigned int mach_error_t; 20 | #elif defined(__APPLE__) 21 | #include 22 | #include 23 | #endif 24 | 25 | /* Error codes */ 26 | #define MDERR_APPLE_MOBILE (err_system(0x3a)) 27 | #define MDERR_IPHONE (err_sub(0)) 28 | 29 | /* Apple Mobile (AM*) errors */ 30 | #define MDERR_OK ERR_SUCCESS 31 | #define MDERR_SYSCALL (ERR_MOBILE_DEVICE | 0x01) 32 | #define MDERR_OUT_OF_MEMORY (ERR_MOBILE_DEVICE | 0x03) 33 | #define MDERR_QUERY_FAILED (ERR_MOBILE_DEVICE | 0x04) 34 | #define MDERR_INVALID_ARGUMENT (ERR_MOBILE_DEVICE | 0x0b) 35 | #define MDERR_DICT_NOT_LOADED (ERR_MOBILE_DEVICE | 0x25) 36 | 37 | /* Apple File Connection (AFC*) errors */ 38 | #define MDERR_AFC_OUT_OF_MEMORY 0x03 39 | 40 | /* USBMux errors */ 41 | #define MDERR_USBMUX_ARG_NULL 0x16 42 | #define MDERR_USBMUX_FAILED 0xffffffff 43 | 44 | /* Messages passed to device notification callbacks: passed as part of 45 | * am_device_notification_callback_info. */ 46 | #define ADNCI_MSG_CONNECTED 1 47 | #define ADNCI_MSG_DISCONNECTED 2 48 | #define ADNCI_MSG_UNKNOWN 3 49 | 50 | #define AMD_IPHONE_PRODUCT_ID 0x1290 51 | #define AMD_IPHONE_SERIAL "3391002d9c804d105e2c8c7d94fc35b6f3d214a3" 52 | 53 | /* Services, found in /System/Library/Lockdown/Services.plist */ 54 | #define AMSVC_AFC CFSTR("com.apple.afc") 55 | #define AMSVC_BACKUP CFSTR("com.apple.mobilebackup") 56 | #define AMSVC_CRASH_REPORT_COPY CFSTR("com.apple.crashreportcopy") 57 | #define AMSVC_DEBUG_IMAGE_MOUNT CFSTR("com.apple.mobile.debug_image_mount") 58 | #define AMSVC_NOTIFICATION_PROXY CFSTR("com.apple.mobile.notification_proxy") 59 | #define AMSVC_PURPLE_TEST CFSTR("com.apple.purpletestr") 60 | #define AMSVC_SOFTWARE_UPDATE CFSTR("com.apple.mobile.software_update") 61 | #define AMSVC_SYNC CFSTR("com.apple.mobilesync") 62 | #define AMSVC_SCREENSHOT CFSTR("com.apple.screenshotr") 63 | #define AMSVC_SYSLOG_RELAY CFSTR("com.apple.syslog_relay") 64 | #define AMSVC_SYSTEM_PROFILER CFSTR("com.apple.mobile.system_profiler") 65 | 66 | typedef unsigned int afc_error_t; 67 | typedef unsigned int usbmux_error_t; 68 | typedef unsigned int service_conn_t; 69 | 70 | struct am_recovery_device; 71 | 72 | typedef struct am_device_notification_callback_info { 73 | struct am_device *dev; /* 0 device */ 74 | unsigned int msg; /* 4 one of ADNCI_MSG_* */ 75 | } __attribute__ ((packed)) am_device_notification_callback_info; 76 | 77 | /* The type of the device restore notification callback functions. 78 | * TODO: change to correct type. */ 79 | typedef void (*am_restore_device_notification_callback)(struct 80 | am_recovery_device *); 81 | 82 | /* This is a CoreFoundation object of class AMRecoveryModeDevice. */ 83 | typedef struct am_recovery_device { 84 | unsigned char unknown0[8]; /* 0 */ 85 | am_restore_device_notification_callback callback; /* 8 */ 86 | void *user_info; /* 12 */ 87 | unsigned char unknown1[12]; /* 16 */ 88 | unsigned int readwrite_pipe; /* 28 */ 89 | unsigned char read_pipe; /* 32 */ 90 | unsigned char write_ctrl_pipe; /* 33 */ 91 | unsigned char read_unknown_pipe; /* 34 */ 92 | unsigned char write_file_pipe; /* 35 */ 93 | unsigned char write_input_pipe; /* 36 */ 94 | } __attribute__ ((packed)) am_recovery_device; 95 | 96 | /* A CoreFoundation object of class AMRestoreModeDevice. */ 97 | typedef struct am_restore_device { 98 | unsigned char unknown[32]; 99 | int port; 100 | } __attribute__ ((packed)) am_restore_device; 101 | 102 | /* The type of the device notification callback function. */ 103 | typedef void(*am_device_notification_callback)(struct 104 | am_device_notification_callback_info *, void* arg); 105 | 106 | /* The type of the _AMDDeviceAttached function. 107 | * TODO: change to correct type. */ 108 | typedef void *amd_device_attached_callback; 109 | 110 | 111 | typedef struct am_device { 112 | unsigned char unknown0[16]; /* 0 - zero */ 113 | unsigned int device_id; /* 16 */ 114 | unsigned int product_id; /* 20 - set to AMD_IPHONE_PRODUCT_ID */ 115 | char *serial; /* 24 - set to AMD_IPHONE_SERIAL */ 116 | unsigned int unknown1; /* 28 */ 117 | unsigned char unknown2[4]; /* 32 */ 118 | unsigned int lockdown_conn; /* 36 */ 119 | unsigned char unknown3[8]; /* 40 */ 120 | } __attribute__ ((packed)) am_device; 121 | 122 | typedef struct am_device_notification { 123 | unsigned int unknown0; /* 0 */ 124 | unsigned int unknown1; /* 4 */ 125 | unsigned int unknown2; /* 8 */ 126 | am_device_notification_callback callback; /* 12 */ 127 | unsigned int unknown3; /* 16 */ 128 | } __attribute__ ((packed)) am_device_notification; 129 | 130 | typedef struct afc_connection { 131 | unsigned int handle; /* 0 */ 132 | unsigned int unknown0; /* 4 */ 133 | unsigned char unknown1; /* 8 */ 134 | unsigned char padding[3]; /* 9 */ 135 | unsigned int unknown2; /* 12 */ 136 | unsigned int unknown3; /* 16 */ 137 | unsigned int unknown4; /* 20 */ 138 | unsigned int fs_block_size; /* 24 */ 139 | unsigned int sock_block_size; /* 28: always 0x3c */ 140 | unsigned int io_timeout; /* 32: from AFCConnectionOpen, usu. 0 */ 141 | void *afc_lock; /* 36 */ 142 | unsigned int context; /* 40 */ 143 | } __attribute__ ((packed)) afc_connection; 144 | 145 | typedef struct afc_directory { 146 | unsigned char unknown[0]; /* size unknown */ 147 | } __attribute__ ((packed)) afc_directory; 148 | 149 | typedef struct afc_dictionary { 150 | unsigned char unknown[0]; /* size unknown */ 151 | } __attribute__ ((packed)) afc_dictionary; 152 | 153 | typedef unsigned long long afc_file_ref; 154 | 155 | typedef struct usbmux_listener_1 { /* offset value in iTunes */ 156 | unsigned int unknown0; /* 0 1 */ 157 | unsigned char *unknown1; /* 4 ptr, maybe device? */ 158 | amd_device_attached_callback callback; /* 8 _AMDDeviceAttached */ 159 | unsigned int unknown3; /* 12 */ 160 | unsigned int unknown4; /* 16 */ 161 | unsigned int unknown5; /* 20 */ 162 | } __attribute__ ((packed)) usbmux_listener_1; 163 | 164 | typedef struct usbmux_listener_2 { 165 | unsigned char unknown0[4144]; 166 | } __attribute__ ((packed)) usbmux_listener_2; 167 | 168 | typedef struct am_bootloader_control_packet { 169 | unsigned char opcode; /* 0 */ 170 | unsigned char length; /* 1 */ 171 | unsigned char magic[2]; /* 2: 0x34, 0x12 */ 172 | unsigned char payload[0]; /* 4 */ 173 | } __attribute__ ((packed)) am_bootloader_control_packet; 174 | 175 | /* ---------------------------------------------------------------------------- 176 | * Public routines 177 | * ------------------------------------------------------------------------- */ 178 | 179 | void AMDSetLogLevel(int level); 180 | 181 | /* Registers a notification with the current run loop. The callback gets 182 | * copied into the notification struct, as well as being registered with the 183 | * current run loop. dn_unknown3 gets copied into unknown3 in the same. 184 | * (Maybe dn_unknown3 is a user info parameter that gets passed as an arg to 185 | * the callback?) unused0 and unused1 are both 0 when iTunes calls this. 186 | * In iTunes the callback is located from $3db78e-$3dbbaf. 187 | * 188 | * Returns: 189 | * MDERR_OK if successful 190 | * MDERR_SYSCALL if CFRunLoopAddSource() failed 191 | * MDERR_OUT_OF_MEMORY if we ran out of memory 192 | */ 193 | 194 | mach_error_t AMDeviceNotificationSubscribe(am_device_notification_callback 195 | callback, unsigned int unused0, unsigned int unused1, void* //unsigned int 196 | dn_unknown3, struct am_device_notification **notification); 197 | 198 | 199 | /* Connects to the iPhone. Pass in the am_device structure that the 200 | * notification callback will give to you. 201 | * 202 | * Returns: 203 | * MDERR_OK if successfully connected 204 | * MDERR_SYSCALL if setsockopt() failed 205 | * MDERR_QUERY_FAILED if the daemon query failed 206 | * MDERR_INVALID_ARGUMENT if USBMuxConnectByPort returned 0xffffffff 207 | */ 208 | 209 | mach_error_t AMDeviceConnect(struct am_device *device); 210 | 211 | /* Calls PairingRecordPath() on the given device, than tests whether the path 212 | * which that function returns exists. During the initial connect, the path 213 | * returned by that function is '/', and so this returns 1. 214 | * 215 | * Returns: 216 | * 0 if the path did not exist 217 | * 1 if it did 218 | */ 219 | 220 | int AMDeviceIsPaired(struct am_device *device); 221 | 222 | /* iTunes calls this function immediately after testing whether the device is 223 | * paired. It creates a pairing file and establishes a Lockdown connection. 224 | * 225 | * Returns: 226 | * MDERR_OK if successful 227 | * MDERR_INVALID_ARGUMENT if the supplied device is null 228 | * MDERR_DICT_NOT_LOADED if the load_dict() call failed 229 | */ 230 | 231 | mach_error_t AMDeviceValidatePairing(struct am_device *device); 232 | 233 | /* Creates a Lockdown session and adjusts the device structure appropriately 234 | * to indicate that the session has been started. iTunes calls this function 235 | * after validating pairing. 236 | * 237 | * Returns: 238 | * MDERR_OK if successful 239 | * MDERR_INVALID_ARGUMENT if the Lockdown conn has not been established 240 | * MDERR_DICT_NOT_LOADED if the load_dict() call failed 241 | */ 242 | 243 | mach_error_t AMDeviceStartSession(struct am_device *device); 244 | 245 | /* Starts a service and returns a handle that can be used in order to further 246 | * access the service. You should stop the session and disconnect before using 247 | * the service. iTunes calls this function after starting a session. It starts 248 | * the service and the SSL connection. unknown may safely be 249 | * NULL (it is when iTunes calls this), but if it is not, then it will be 250 | * filled upon function exit. service_name should be one of the AMSVC_* 251 | * constants. If the service is AFC (AMSVC_AFC), then the handle is the handle 252 | * that will be used for further AFC* calls. 253 | * 254 | * Returns: 255 | * MDERR_OK if successful 256 | * MDERR_SYSCALL if the setsockopt() call failed 257 | * MDERR_INVALID_ARGUMENT if the Lockdown conn has not been established 258 | */ 259 | 260 | mach_error_t AMDeviceStartService(struct am_device *device, CFStringRef 261 | service_name, service_conn_t *handle, unsigned int * 262 | unknown); 263 | 264 | mach_error_t AMDeviceStartHouseArrestService(struct am_device *device, CFStringRef identifier, void *unknown, service_conn_t *handle, unsigned int *what); 265 | 266 | /* Stops a session. You should do this before accessing services. 267 | * 268 | * Returns: 269 | * MDERR_OK if successful 270 | * MDERR_INVALID_ARGUMENT if the Lockdown conn has not been established 271 | */ 272 | 273 | mach_error_t AMDeviceStopSession(struct am_device *device); 274 | 275 | /* Opens an Apple File Connection. You must start the appropriate service 276 | * first with AMDeviceStartService(). In iTunes, io_timeout is 0. 277 | * 278 | * Returns: 279 | * MDERR_OK if successful 280 | * MDERR_AFC_OUT_OF_MEMORY if malloc() failed 281 | */ 282 | 283 | afc_error_t AFCConnectionOpen(service_conn_t handle, unsigned int io_timeout, 284 | struct afc_connection **conn); 285 | 286 | /* Pass in a pointer to an afc_device_info structure. It will be filled. */ 287 | afc_error_t AFCDeviceInfoOpen(afc_connection *conn, struct 288 | afc_dictionary **info); 289 | 290 | /* Turns debug mode on if the environment variable AFCDEBUG is set to a numeric 291 | * value, or if the file '/AFCDEBUG' is present and contains a value. */ 292 | void AFCPlatformInit(); 293 | 294 | /* Opens a directory on the iPhone. Pass in a pointer in dir to be filled in. 295 | * Note that this normally only accesses the iTunes sandbox/partition as the 296 | * root, which is /var/root/Media. Pathnames are specified with '/' delimiters 297 | * as in Unix style. 298 | * 299 | * Returns: 300 | * MDERR_OK if successful 301 | */ 302 | 303 | afc_error_t AFCDirectoryOpen(afc_connection *conn, const char *path, 304 | struct afc_directory **dir); 305 | 306 | /* Acquires the next entry in a directory previously opened with 307 | * AFCDirectoryOpen(). When dirent is filled with a NULL value, then the end 308 | * of the directory has been reached. '.' and '..' will be returned as the 309 | * first two entries in each directory except the root; you may want to skip 310 | * over them. 311 | * 312 | * Returns: 313 | * MDERR_OK if successful, even if no entries remain 314 | */ 315 | 316 | afc_error_t AFCDirectoryRead(afc_connection *conn/*unsigned int unused*/, struct afc_directory *dir, 317 | char **dirent); 318 | 319 | afc_error_t AFCDirectoryClose(afc_connection *conn, struct afc_directory *dir); 320 | afc_error_t AFCDirectoryCreate(afc_connection *conn, const char *dirname); 321 | afc_error_t AFCRemovePath(afc_connection *conn, const char *dirname); 322 | afc_error_t AFCRenamePath(afc_connection *conn, const char *from, const char *to); 323 | afc_error_t AFCLinkPath(afc_connection *conn, long long int linktype, const char *target, const char *linkname); 324 | 325 | /* Returns the context field of the given AFC connection. */ 326 | unsigned int AFCConnectionGetContext(afc_connection *conn); 327 | 328 | /* Returns the fs_block_size field of the given AFC connection. */ 329 | unsigned int AFCConnectionGetFSBlockSize(afc_connection *conn); 330 | 331 | /* Returns the io_timeout field of the given AFC connection. In iTunes this is 332 | * 0. */ 333 | unsigned int AFCConnectionGetIOTimeout(afc_connection *conn); 334 | 335 | /* Returns the sock_block_size field of the given AFC connection. */ 336 | unsigned int AFCConnectionGetSocketBlockSize(afc_connection *conn); 337 | 338 | /* Closes the given AFC connection. */ 339 | afc_error_t AFCConnectionClose(afc_connection *conn); 340 | 341 | /* Registers for device notifications related to the restore process. unknown0 342 | * is zero when iTunes calls this. In iTunes, 343 | * the callbacks are located at: 344 | * 1: $3ac68e-$3ac6b1, calls $3ac542(unknown1, arg, 0) 345 | * 2: $3ac66a-$3ac68d, calls $3ac542(unknown1, 0, arg) 346 | * 3: $3ac762-$3ac785, calls $3ac6b2(unknown1, arg, 0) 347 | * 4: $3ac73e-$3ac761, calls $3ac6b2(unknown1, 0, arg) 348 | */ 349 | 350 | unsigned int AMRestoreRegisterForDeviceNotifications( 351 | am_restore_device_notification_callback dfu_connect_callback, 352 | am_restore_device_notification_callback recovery_connect_callback, 353 | am_restore_device_notification_callback dfu_disconnect_callback, 354 | am_restore_device_notification_callback recovery_disconnect_callback, 355 | unsigned int unknown0, 356 | void *user_info); 357 | 358 | /* Causes the restore functions to spit out (unhelpful) progress messages to 359 | * the file specified by the given path. iTunes always calls this right before 360 | * restoring with a path of 361 | * "$HOME/Library/Logs/iPhone Updater Logs/iPhoneUpdater X.log", where X is an 362 | * unused number. 363 | */ 364 | 365 | unsigned int AMRestoreEnableFileLogging(char *path); 366 | 367 | /* Initializes a new option dictionary to default values. Pass the constant 368 | * kCFAllocatorDefault as the allocator. The option dictionary looks as 369 | * follows: 370 | * { 371 | * NORImageType => 'production', 372 | * AutoBootDelay => 0, 373 | * KernelCacheType => 'Release', 374 | * UpdateBaseband => true, 375 | * DFUFileType => 'RELEASE', 376 | * SystemImageType => 'User', 377 | * CreateFilesystemPartitions => true, 378 | * FlashNOR => true, 379 | * RestoreBootArgs => 'rd=md0 nand-enable-reformat=1 -progress' 380 | * BootImageType => 'User' 381 | * } 382 | * 383 | * Returns: 384 | * the option dictionary if successful 385 | * NULL if out of memory 386 | */ 387 | 388 | CFMutableDictionaryRef AMRestoreCreateDefaultOptions(CFAllocatorRef allocator); 389 | 390 | /* ---------------------------------------------------------------------------- 391 | * Less-documented public routines 392 | * ------------------------------------------------------------------------- */ 393 | 394 | /* mode 2 = read, mode 3 = write */ 395 | afc_error_t AFCFileRefOpen(afc_connection *conn, const char *path, 396 | unsigned long long mode, afc_file_ref *ref); 397 | afc_error_t AFCFileRefSeek(afc_connection *conn, afc_file_ref ref, 398 | unsigned long long offset1, unsigned long long offset2); 399 | afc_error_t AFCFileRefRead(afc_connection *conn, afc_file_ref ref, 400 | void *buf, size_t *len); 401 | afc_error_t AFCFileRefSetFileSize(afc_connection *conn, afc_file_ref ref, 402 | unsigned long long offset); 403 | afc_error_t AFCFileRefWrite(afc_connection *conn, afc_file_ref ref, 404 | const void *buf, size_t len); 405 | afc_error_t AFCFileRefClose(afc_connection *conn, afc_file_ref ref); 406 | 407 | afc_error_t AFCFileInfoOpen(afc_connection *conn, const char *path, struct 408 | afc_dictionary **info); 409 | afc_error_t AFCKeyValueRead(struct afc_dictionary *dict, char **key, char ** 410 | val); 411 | afc_error_t AFCKeyValueClose(struct afc_dictionary *dict); 412 | 413 | unsigned int AMRestorePerformRecoveryModeRestore(struct am_recovery_device * 414 | rdev, CFDictionaryRef opts, void *callback, void *user_info); 415 | unsigned int AMRestorePerformRestoreModeRestore(struct am_restore_device * 416 | rdev, CFDictionaryRef opts, void *callback, void *user_info); 417 | 418 | struct am_restore_device *AMRestoreModeDeviceCreate(unsigned int unknown0, 419 | unsigned int connection_id, unsigned int unknown1); 420 | 421 | unsigned int AMRestoreCreatePathsForBundle(CFStringRef restore_bundle_path, 422 | CFStringRef kernel_cache_type, CFStringRef boot_image_type, unsigned int 423 | unknown0, CFStringRef *firmware_dir_path, CFStringRef * 424 | kernelcache_restore_path, unsigned int unknown1, CFStringRef * 425 | ramdisk_path); 426 | 427 | unsigned int AMDeviceGetConnectionID(struct am_device *device); 428 | mach_error_t AMDeviceEnterRecovery(struct am_device *device); 429 | mach_error_t AMDeviceDisconnect(struct am_device *device); 430 | mach_error_t AMDeviceRetain(struct am_device *device); 431 | mach_error_t AMDeviceRelease(struct am_device *device); 432 | CFStringRef AMDeviceCopyValue(struct am_device *device, unsigned int, CFStringRef cfstring); 433 | CFStringRef AMDeviceCopyDeviceIdentifier(struct am_device *device); 434 | 435 | typedef void (*notify_callback)(CFStringRef notification, void *data); 436 | 437 | mach_error_t AMDPostNotification(service_conn_t socket, CFStringRef notification, CFStringRef userinfo); 438 | mach_error_t AMDObserveNotification(void *socket, CFStringRef notification); 439 | mach_error_t AMDListenForNotifications(void *socket, notify_callback cb, void *data); 440 | mach_error_t AMDShutdownNotificationProxy(void *socket); 441 | 442 | /*edits by geohot*/ 443 | mach_error_t AMDeviceDeactivate(struct am_device *device); 444 | mach_error_t AMDeviceActivate(struct am_device *device, CFMutableDictionaryRef); 445 | /*end*/ 446 | 447 | void *AMDeviceSerialize(struct am_device *device); 448 | void AMDAddLogFileDescriptor(int fd); 449 | //kern_return_t AMDeviceSendMessage(service_conn_t socket, void *unused, CFPropertyListRef plist); 450 | //kern_return_t AMDeviceReceiveMessage(service_conn_t socket, CFDictionaryRef options, CFPropertyListRef * result); 451 | 452 | typedef int (*am_device_install_application_callback)(CFDictionaryRef, int); 453 | 454 | mach_error_t AMDeviceInstallApplication(service_conn_t socket, CFStringRef path, CFDictionaryRef options, am_device_install_application_callback callback, void *user); 455 | mach_error_t AMDeviceTransferApplication(service_conn_t socket, CFStringRef path, CFDictionaryRef options, am_device_install_application_callback callbackj, void *user); 456 | 457 | int AMDeviceSecureUninstallApplication(int unknown0, struct am_device *device, CFStringRef bundle_id, int unknown1, void *callback, int callback_arg); 458 | 459 | /* ---------------------------------------------------------------------------- 460 | * Semi-private routines 461 | * ------------------------------------------------------------------------- */ 462 | 463 | /* Pass in a usbmux_listener_1 structure and a usbmux_listener_2 structure 464 | * pointer, which will be filled with the resulting usbmux_listener_2. 465 | * 466 | * Returns: 467 | * MDERR_OK if completed successfully 468 | * MDERR_USBMUX_ARG_NULL if one of the arguments was NULL 469 | * MDERR_USBMUX_FAILED if the listener was not created successfully 470 | */ 471 | 472 | usbmux_error_t USBMuxListenerCreate(struct usbmux_listener_1 *esi_fp8, struct 473 | usbmux_listener_2 **eax_fp12); 474 | 475 | /* ---------------------------------------------------------------------------- 476 | * Less-documented semi-private routines 477 | * ------------------------------------------------------------------------- */ 478 | 479 | usbmux_error_t USBMuxListenerHandleData(void *); 480 | 481 | /* ---------------------------------------------------------------------------- 482 | * Private routines - here be dragons 483 | * ------------------------------------------------------------------------- */ 484 | 485 | /* AMRestorePerformRestoreModeRestore() calls this function with a dictionary 486 | * in order to perform certain special restore operations 487 | * (RESTORED_OPERATION_*). It is thought that this function might enable 488 | * significant access to the phone. */ 489 | 490 | typedef unsigned int (*t_performOperation)(struct am_restore_device *rdev, 491 | CFDictionaryRef op); // __attribute__ ((regparm(2))); 492 | 493 | #ifdef __cplusplus 494 | } 495 | #endif 496 | 497 | #endif 498 | -------------------------------------------------------------------------------- /ios-deploy.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7E70899E1B587F29004D23AA /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E70899D1B587F29004D23AA /* CoreFoundation.framework */; }; 11 | 7E7089A01B58801E004D23AA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E70899F1B58801E004D23AA /* Foundation.framework */; }; 12 | 7E8E3A861C45D4CE0017F6C1 /* ios_deploy_tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E8E3A851C45D4CE0017F6C1 /* ios_deploy_tests.m */; }; 13 | 7E8E3A921C45D5380017F6C1 /* libios_deploy.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E8E3A911C45D5380017F6C1 /* libios_deploy.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | 7E8E3A941C45D5380017F6C1 /* libios_deploy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E8E3A931C45D5380017F6C1 /* libios_deploy.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 15 | 7E8E3A9B1C45D5970017F6C1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E70899F1B58801E004D23AA /* Foundation.framework */; }; 16 | 7E8E3A9D1C45D6290017F6C1 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E70899D1B587F29004D23AA /* CoreFoundation.framework */; }; 17 | 7EDCC3CD1C45DC94002F9851 /* ios-deploy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E7089991B587DE4004D23AA /* ios-deploy.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | 7E8E3A991C45D5850017F6C1 /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = 7E7089861B587BF3004D23AA /* Project object */; 24 | proxyType = 1; 25 | remoteGlobalIDString = 7E8E3A8E1C45D5380017F6C1; 26 | remoteInfo = "ios-deploy-lib"; 27 | }; 28 | 7EDCC3CA1C45D933002F9851 /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 7E7089861B587BF3004D23AA /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = 7E8E3A8E1C45D5380017F6C1; 33 | remoteInfo = "ios-deploy-lib"; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 7B28C98C1DC10655009569B6 /* device_db.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = device_db.h; sourceTree = ""; }; 39 | 7E1C00CC1C3C93AF00D686B5 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = ""; }; 40 | 7E1C00CF1C3C9ABB00D686B5 /* lldb.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = lldb.py; path = src/scripts/lldb.py; sourceTree = SOURCE_ROOT; }; 41 | 7E1C00D11C3C9CB000D686B5 /* lldb.py.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lldb.py.h; sourceTree = ""; }; 42 | 7E70898E1B587BF3004D23AA /* ios-deploy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "ios-deploy"; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 7E7089991B587DE4004D23AA /* ios-deploy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ios-deploy.m"; sourceTree = ""; }; 44 | 7E70899A1B587DE4004D23AA /* errors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = errors.h; sourceTree = ""; }; 45 | 7E70899B1B587DE4004D23AA /* MobileDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobileDevice.h; sourceTree = ""; }; 46 | 7E70899D1B587F29004D23AA /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 47 | 7E70899F1B58801E004D23AA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 48 | 7E8E3A831C45D4CE0017F6C1 /* ios-deploy-tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ios-deploy-tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 7E8E3A851C45D4CE0017F6C1 /* ios_deploy_tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ios_deploy_tests.m; sourceTree = ""; }; 50 | 7E8E3A871C45D4CE0017F6C1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | 7E8E3A8F1C45D5380017F6C1 /* libios-deploy.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libios-deploy.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 7E8E3A911C45D5380017F6C1 /* libios_deploy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libios_deploy.h; sourceTree = ""; }; 53 | 7E8E3A931C45D5380017F6C1 /* libios_deploy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = libios_deploy.m; sourceTree = ""; }; 54 | 7EDCC3CE1C45DFF0002F9851 /* check_reqs.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = check_reqs.js; sourceTree = ""; }; 55 | /* End PBXFileReference section */ 56 | 57 | /* Begin PBXFrameworksBuildPhase section */ 58 | 7E70898B1B587BF3004D23AA /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | 7E7089A01B58801E004D23AA /* Foundation.framework in Frameworks */, 63 | 7E70899E1B587F29004D23AA /* CoreFoundation.framework in Frameworks */, 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | 7E8E3A801C45D4CE0017F6C1 /* Frameworks */ = { 68 | isa = PBXFrameworksBuildPhase; 69 | buildActionMask = 2147483647; 70 | files = ( 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | 7E8E3A8C1C45D5380017F6C1 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | 7E8E3A9D1C45D6290017F6C1 /* CoreFoundation.framework in Frameworks */, 79 | 7E8E3A9B1C45D5970017F6C1 /* Foundation.framework in Frameworks */, 80 | ); 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | /* End PBXFrameworksBuildPhase section */ 84 | 85 | /* Begin PBXGroup section */ 86 | 7E1C00CE1C3C9A7700D686B5 /* scripts */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 7EDCC3CE1C45DFF0002F9851 /* check_reqs.js */, 90 | 7E1C00CF1C3C9ABB00D686B5 /* lldb.py */, 91 | ); 92 | name = scripts; 93 | path = src/scripts; 94 | sourceTree = ""; 95 | }; 96 | 7E7089851B587BF3004D23AA = { 97 | isa = PBXGroup; 98 | children = ( 99 | 7E1C00CE1C3C9A7700D686B5 /* scripts */, 100 | 7E7089901B587BF3004D23AA /* ios-deploy */, 101 | 7E8E3A841C45D4CE0017F6C1 /* ios-deploy-tests */, 102 | 7E8E3A901C45D5380017F6C1 /* ios-deploy-lib */, 103 | 7E7089A21B588219004D23AA /* Frameworks */, 104 | 7E70898F1B587BF3004D23AA /* Products */, 105 | ); 106 | sourceTree = ""; 107 | }; 108 | 7E70898F1B587BF3004D23AA /* Products */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 7E70898E1B587BF3004D23AA /* ios-deploy */, 112 | 7E8E3A831C45D4CE0017F6C1 /* ios-deploy-tests.xctest */, 113 | 7E8E3A8F1C45D5380017F6C1 /* libios-deploy.a */, 114 | ); 115 | name = Products; 116 | sourceTree = ""; 117 | }; 118 | 7E7089901B587BF3004D23AA /* ios-deploy */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 7E1C00D11C3C9CB000D686B5 /* lldb.py.h */, 122 | 7E1C00CC1C3C93AF00D686B5 /* version.h */, 123 | 7E7089991B587DE4004D23AA /* ios-deploy.m */, 124 | 7E70899A1B587DE4004D23AA /* errors.h */, 125 | 7E70899B1B587DE4004D23AA /* MobileDevice.h */, 126 | 7B28C98C1DC10655009569B6 /* device_db.h */, 127 | ); 128 | name = "ios-deploy"; 129 | path = "src/ios-deploy"; 130 | sourceTree = ""; 131 | }; 132 | 7E7089A21B588219004D23AA /* Frameworks */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 7E70899F1B58801E004D23AA /* Foundation.framework */, 136 | 7E70899D1B587F29004D23AA /* CoreFoundation.framework */, 137 | ); 138 | name = Frameworks; 139 | sourceTree = ""; 140 | }; 141 | 7E8E3A841C45D4CE0017F6C1 /* ios-deploy-tests */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 7E8E3A851C45D4CE0017F6C1 /* ios_deploy_tests.m */, 145 | 7E8E3A871C45D4CE0017F6C1 /* Info.plist */, 146 | ); 147 | name = "ios-deploy-tests"; 148 | path = "src/ios-deploy-tests"; 149 | sourceTree = ""; 150 | }; 151 | 7E8E3A901C45D5380017F6C1 /* ios-deploy-lib */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | 7E8E3A911C45D5380017F6C1 /* libios_deploy.h */, 155 | 7E8E3A931C45D5380017F6C1 /* libios_deploy.m */, 156 | ); 157 | name = "ios-deploy-lib"; 158 | path = "src/ios-deploy-lib"; 159 | sourceTree = ""; 160 | }; 161 | /* End PBXGroup section */ 162 | 163 | /* Begin PBXHeadersBuildPhase section */ 164 | 7E8E3A8D1C45D5380017F6C1 /* Headers */ = { 165 | isa = PBXHeadersBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | 7E8E3A921C45D5380017F6C1 /* libios_deploy.h in Headers */, 169 | ); 170 | runOnlyForDeploymentPostprocessing = 0; 171 | }; 172 | /* End PBXHeadersBuildPhase section */ 173 | 174 | /* Begin PBXNativeTarget section */ 175 | 7E70898D1B587BF3004D23AA /* ios-deploy */ = { 176 | isa = PBXNativeTarget; 177 | buildConfigurationList = 7E7089951B587BF3004D23AA /* Build configuration list for PBXNativeTarget "ios-deploy" */; 178 | buildPhases = ( 179 | 7EDCC3CF1C45E03B002F9851 /* ShellScript */, 180 | C0CD3D981F59D20100F954DB /* ShellScript */, 181 | 7E70898B1B587BF3004D23AA /* Frameworks */, 182 | 7EDCC3CC1C45DC89002F9851 /* Sources */, 183 | C0CD3D9B1F59DA8300F954DB /* Run Script */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | 7E8E3A9A1C45D5850017F6C1 /* PBXTargetDependency */, 189 | ); 190 | name = "ios-deploy"; 191 | productName = "ios-deploy"; 192 | productReference = 7E70898E1B587BF3004D23AA /* ios-deploy */; 193 | productType = "com.apple.product-type.tool"; 194 | }; 195 | 7E8E3A821C45D4CE0017F6C1 /* ios-deploy-tests */ = { 196 | isa = PBXNativeTarget; 197 | buildConfigurationList = 7E8E3A8A1C45D4CE0017F6C1 /* Build configuration list for PBXNativeTarget "ios-deploy-tests" */; 198 | buildPhases = ( 199 | 3BF32EF31F5A215300E1699B /* ShellScript */, 200 | 7E8E3A7F1C45D4CE0017F6C1 /* Sources */, 201 | 7E8E3A801C45D4CE0017F6C1 /* Frameworks */, 202 | 7E8E3A811C45D4CE0017F6C1 /* Resources */, 203 | 3BF32EF41F5A217100E1699B /* ShellScript */, 204 | ); 205 | buildRules = ( 206 | ); 207 | dependencies = ( 208 | 7EDCC3CB1C45D933002F9851 /* PBXTargetDependency */, 209 | ); 210 | name = "ios-deploy-tests"; 211 | productName = "ios-deploy-tests"; 212 | productReference = 7E8E3A831C45D4CE0017F6C1 /* ios-deploy-tests.xctest */; 213 | productType = "com.apple.product-type.bundle.unit-test"; 214 | }; 215 | 7E8E3A8E1C45D5380017F6C1 /* ios-deploy-lib */ = { 216 | isa = PBXNativeTarget; 217 | buildConfigurationList = 7E8E3A951C45D5380017F6C1 /* Build configuration list for PBXNativeTarget "ios-deploy-lib" */; 218 | buildPhases = ( 219 | 7E8E3A8B1C45D5380017F6C1 /* Sources */, 220 | 7E8E3A8C1C45D5380017F6C1 /* Frameworks */, 221 | 7E8E3A8D1C45D5380017F6C1 /* Headers */, 222 | ); 223 | buildRules = ( 224 | ); 225 | dependencies = ( 226 | ); 227 | name = "ios-deploy-lib"; 228 | productName = "ios-deploy-lib"; 229 | productReference = 7E8E3A8F1C45D5380017F6C1 /* libios-deploy.a */; 230 | productType = "com.apple.product-type.library.static"; 231 | }; 232 | /* End PBXNativeTarget section */ 233 | 234 | /* Begin PBXProject section */ 235 | 7E7089861B587BF3004D23AA /* Project object */ = { 236 | isa = PBXProject; 237 | attributes = { 238 | LastUpgradeCheck = 0800; 239 | ORGANIZATIONNAME = PhoneGap; 240 | TargetAttributes = { 241 | 7E70898D1B587BF3004D23AA = { 242 | CreatedOnToolsVersion = 6.4; 243 | }; 244 | 7E8E3A821C45D4CE0017F6C1 = { 245 | CreatedOnToolsVersion = 7.2; 246 | }; 247 | 7E8E3A8E1C45D5380017F6C1 = { 248 | CreatedOnToolsVersion = 7.2; 249 | }; 250 | }; 251 | }; 252 | buildConfigurationList = 7E7089891B587BF3004D23AA /* Build configuration list for PBXProject "ios-deploy" */; 253 | compatibilityVersion = "Xcode 3.2"; 254 | developmentRegion = English; 255 | hasScannedForEncodings = 0; 256 | knownRegions = ( 257 | en, 258 | Base, 259 | ); 260 | mainGroup = 7E7089851B587BF3004D23AA; 261 | productRefGroup = 7E70898F1B587BF3004D23AA /* Products */; 262 | projectDirPath = ""; 263 | projectRoot = ""; 264 | targets = ( 265 | 7E70898D1B587BF3004D23AA /* ios-deploy */, 266 | 7E8E3A821C45D4CE0017F6C1 /* ios-deploy-tests */, 267 | 7E8E3A8E1C45D5380017F6C1 /* ios-deploy-lib */, 268 | ); 269 | }; 270 | /* End PBXProject section */ 271 | 272 | /* Begin PBXResourcesBuildPhase section */ 273 | 7E8E3A811C45D4CE0017F6C1 /* Resources */ = { 274 | isa = PBXResourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | /* End PBXResourcesBuildPhase section */ 281 | 282 | /* Begin PBXShellScriptBuildPhase section */ 283 | 3BF32EF31F5A215300E1699B /* ShellScript */ = { 284 | isa = PBXShellScriptBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | ); 288 | inputPaths = ( 289 | ); 290 | outputPaths = ( 291 | ); 292 | runOnlyForDeploymentPostprocessing = 0; 293 | shellPath = /bin/sh; 294 | shellScript = "mkdir -p \"${PROJECT_DIR}/_Frameworks\"\ncp -r /System/Library/PrivateFrameworks/MobileDevice.framework \"${PROJECT_DIR}/_Frameworks\""; 295 | }; 296 | 3BF32EF41F5A217100E1699B /* ShellScript */ = { 297 | isa = PBXShellScriptBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | ); 301 | inputPaths = ( 302 | ); 303 | outputPaths = ( 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | shellPath = /bin/sh; 307 | shellScript = "rm -rf \"${PROJECT_DIR}/_Frameworks\""; 308 | }; 309 | 7EDCC3CF1C45E03B002F9851 /* ShellScript */ = { 310 | isa = PBXShellScriptBuildPhase; 311 | buildActionMask = 2147483647; 312 | files = ( 313 | ); 314 | inputPaths = ( 315 | ); 316 | outputPaths = ( 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | shellPath = /bin/sh; 320 | shellScript = "echo \"\\\"# AUTO-GENERATED - DO NOT MODIFY\\n\\\"\" > src/ios-deploy/lldb.py.h\nawk '{ print \"\\\"\"$0\"\\\\n\\\"\"}' src/scripts/lldb.py >> src/ios-deploy/lldb.py.h"; 321 | }; 322 | C0CD3D981F59D20100F954DB /* ShellScript */ = { 323 | isa = PBXShellScriptBuildPhase; 324 | buildActionMask = 2147483647; 325 | files = ( 326 | ); 327 | inputPaths = ( 328 | ); 329 | outputPaths = ( 330 | ); 331 | runOnlyForDeploymentPostprocessing = 0; 332 | shellPath = /bin/sh; 333 | shellScript = "mkdir -p \"${PROJECT_DIR}/_Frameworks\"\ncp -r /System/Library/PrivateFrameworks/MobileDevice.framework \"${PROJECT_DIR}/_Frameworks\""; 334 | }; 335 | C0CD3D9B1F59DA8300F954DB /* Run Script */ = { 336 | isa = PBXShellScriptBuildPhase; 337 | buildActionMask = 2147483647; 338 | files = ( 339 | ); 340 | inputPaths = ( 341 | ); 342 | name = "Run Script"; 343 | outputPaths = ( 344 | ); 345 | runOnlyForDeploymentPostprocessing = 0; 346 | shellPath = /bin/sh; 347 | shellScript = "rm -rf \"${PROJECT_DIR}/_Frameworks\""; 348 | }; 349 | /* End PBXShellScriptBuildPhase section */ 350 | 351 | /* Begin PBXSourcesBuildPhase section */ 352 | 7E8E3A7F1C45D4CE0017F6C1 /* Sources */ = { 353 | isa = PBXSourcesBuildPhase; 354 | buildActionMask = 2147483647; 355 | files = ( 356 | 7E8E3A861C45D4CE0017F6C1 /* ios_deploy_tests.m in Sources */, 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | }; 360 | 7E8E3A8B1C45D5380017F6C1 /* Sources */ = { 361 | isa = PBXSourcesBuildPhase; 362 | buildActionMask = 2147483647; 363 | files = ( 364 | 7E8E3A941C45D5380017F6C1 /* libios_deploy.m in Sources */, 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | 7EDCC3CC1C45DC89002F9851 /* Sources */ = { 369 | isa = PBXSourcesBuildPhase; 370 | buildActionMask = 2147483647; 371 | files = ( 372 | 7EDCC3CD1C45DC94002F9851 /* ios-deploy.m in Sources */, 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | }; 376 | /* End PBXSourcesBuildPhase section */ 377 | 378 | /* Begin PBXTargetDependency section */ 379 | 7E8E3A9A1C45D5850017F6C1 /* PBXTargetDependency */ = { 380 | isa = PBXTargetDependency; 381 | target = 7E8E3A8E1C45D5380017F6C1 /* ios-deploy-lib */; 382 | targetProxy = 7E8E3A991C45D5850017F6C1 /* PBXContainerItemProxy */; 383 | }; 384 | 7EDCC3CB1C45D933002F9851 /* PBXTargetDependency */ = { 385 | isa = PBXTargetDependency; 386 | target = 7E8E3A8E1C45D5380017F6C1 /* ios-deploy-lib */; 387 | targetProxy = 7EDCC3CA1C45D933002F9851 /* PBXContainerItemProxy */; 388 | }; 389 | /* End PBXTargetDependency section */ 390 | 391 | /* Begin XCBuildConfiguration section */ 392 | 7E7089931B587BF3004D23AA /* Debug */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | ALWAYS_SEARCH_USER_PATHS = NO; 396 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 397 | CLANG_CXX_LIBRARY = "libc++"; 398 | CLANG_ENABLE_MODULES = YES; 399 | CLANG_ENABLE_OBJC_ARC = YES; 400 | CLANG_WARN_BOOL_CONVERSION = YES; 401 | CLANG_WARN_CONSTANT_CONVERSION = YES; 402 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 403 | CLANG_WARN_EMPTY_BODY = YES; 404 | CLANG_WARN_ENUM_CONVERSION = YES; 405 | CLANG_WARN_INFINITE_RECURSION = YES; 406 | CLANG_WARN_INT_CONVERSION = YES; 407 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 408 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 409 | CLANG_WARN_UNREACHABLE_CODE = YES; 410 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 411 | COPY_PHASE_STRIP = NO; 412 | DEBUG_INFORMATION_FORMAT = dwarf; 413 | ENABLE_STRICT_OBJC_MSGSEND = YES; 414 | ENABLE_TESTABILITY = YES; 415 | FRAMEWORK_SEARCH_PATHS = ( 416 | "$(inherited)", 417 | "$(PROJECT_DIR)/_Frameworks", 418 | ); 419 | GCC_C_LANGUAGE_STANDARD = gnu99; 420 | GCC_DYNAMIC_NO_PIC = NO; 421 | GCC_NO_COMMON_BLOCKS = YES; 422 | GCC_OPTIMIZATION_LEVEL = 0; 423 | GCC_PREPROCESSOR_DEFINITIONS = ( 424 | "DEBUG=1", 425 | "$(inherited)", 426 | ); 427 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 428 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 429 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 430 | GCC_WARN_UNDECLARED_SELECTOR = YES; 431 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 432 | GCC_WARN_UNUSED_FUNCTION = YES; 433 | GCC_WARN_UNUSED_VARIABLE = YES; 434 | MACOSX_DEPLOYMENT_TARGET = 10.8; 435 | MTL_ENABLE_DEBUG_INFO = YES; 436 | ONLY_ACTIVE_ARCH = YES; 437 | OTHER_LDFLAGS = ( 438 | "-framework", 439 | MobileDevice, 440 | ); 441 | SDKROOT = macosx; 442 | }; 443 | name = Debug; 444 | }; 445 | 7E7089941B587BF3004D23AA /* Release */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | ALWAYS_SEARCH_USER_PATHS = NO; 449 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 450 | CLANG_CXX_LIBRARY = "libc++"; 451 | CLANG_ENABLE_MODULES = YES; 452 | CLANG_ENABLE_OBJC_ARC = YES; 453 | CLANG_WARN_BOOL_CONVERSION = YES; 454 | CLANG_WARN_CONSTANT_CONVERSION = YES; 455 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 456 | CLANG_WARN_EMPTY_BODY = YES; 457 | CLANG_WARN_ENUM_CONVERSION = YES; 458 | CLANG_WARN_INFINITE_RECURSION = YES; 459 | CLANG_WARN_INT_CONVERSION = YES; 460 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 461 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 462 | CLANG_WARN_UNREACHABLE_CODE = YES; 463 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 464 | COPY_PHASE_STRIP = NO; 465 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 466 | ENABLE_NS_ASSERTIONS = NO; 467 | ENABLE_STRICT_OBJC_MSGSEND = YES; 468 | FRAMEWORK_SEARCH_PATHS = ( 469 | "$(inherited)", 470 | "$(PROJECT_DIR)/_Frameworks", 471 | ); 472 | GCC_C_LANGUAGE_STANDARD = gnu99; 473 | GCC_NO_COMMON_BLOCKS = YES; 474 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 475 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 476 | GCC_WARN_UNDECLARED_SELECTOR = YES; 477 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 478 | GCC_WARN_UNUSED_FUNCTION = YES; 479 | GCC_WARN_UNUSED_VARIABLE = YES; 480 | MACOSX_DEPLOYMENT_TARGET = 10.8; 481 | MTL_ENABLE_DEBUG_INFO = NO; 482 | OTHER_LDFLAGS = ( 483 | "-framework", 484 | MobileDevice, 485 | ); 486 | SDKROOT = macosx; 487 | }; 488 | name = Release; 489 | }; 490 | 7E7089961B587BF3004D23AA /* Debug */ = { 491 | isa = XCBuildConfiguration; 492 | buildSettings = { 493 | PRODUCT_NAME = "$(TARGET_NAME)"; 494 | }; 495 | name = Debug; 496 | }; 497 | 7E7089971B587BF3004D23AA /* Release */ = { 498 | isa = XCBuildConfiguration; 499 | buildSettings = { 500 | PRODUCT_NAME = "$(TARGET_NAME)"; 501 | }; 502 | name = Release; 503 | }; 504 | 7E8E3A881C45D4CE0017F6C1 /* Debug */ = { 505 | isa = XCBuildConfiguration; 506 | buildSettings = { 507 | CODE_SIGN_IDENTITY = "-"; 508 | COMBINE_HIDPI_IMAGES = YES; 509 | INFOPLIST_FILE = "src/ios-deploy-tests/Info.plist"; 510 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 511 | MACOSX_DEPLOYMENT_TARGET = 10.11; 512 | PRODUCT_BUNDLE_IDENTIFIER = "com.phonegap.ios-deploy-tests"; 513 | PRODUCT_NAME = "$(TARGET_NAME)"; 514 | }; 515 | name = Debug; 516 | }; 517 | 7E8E3A891C45D4CE0017F6C1 /* Release */ = { 518 | isa = XCBuildConfiguration; 519 | buildSettings = { 520 | CODE_SIGN_IDENTITY = "-"; 521 | COMBINE_HIDPI_IMAGES = YES; 522 | INFOPLIST_FILE = "src/ios-deploy-tests/Info.plist"; 523 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 524 | MACOSX_DEPLOYMENT_TARGET = 10.11; 525 | PRODUCT_BUNDLE_IDENTIFIER = "com.phonegap.ios-deploy-tests"; 526 | PRODUCT_NAME = "$(TARGET_NAME)"; 527 | }; 528 | name = Release; 529 | }; 530 | 7E8E3A961C45D5380017F6C1 /* Debug */ = { 531 | isa = XCBuildConfiguration; 532 | buildSettings = { 533 | CODE_SIGN_IDENTITY = "-"; 534 | EXECUTABLE_PREFIX = lib; 535 | INSTALL_PATH = ""; 536 | MACOSX_DEPLOYMENT_TARGET = 10.11; 537 | PRODUCT_NAME = "ios-deploy"; 538 | PUBLIC_HEADERS_FOLDER_PATH = ""; 539 | }; 540 | name = Debug; 541 | }; 542 | 7E8E3A971C45D5380017F6C1 /* Release */ = { 543 | isa = XCBuildConfiguration; 544 | buildSettings = { 545 | CODE_SIGN_IDENTITY = "-"; 546 | EXECUTABLE_PREFIX = lib; 547 | INSTALL_PATH = ""; 548 | MACOSX_DEPLOYMENT_TARGET = 10.11; 549 | PRODUCT_NAME = "ios-deploy"; 550 | PUBLIC_HEADERS_FOLDER_PATH = ""; 551 | }; 552 | name = Release; 553 | }; 554 | /* End XCBuildConfiguration section */ 555 | 556 | /* Begin XCConfigurationList section */ 557 | 7E7089891B587BF3004D23AA /* Build configuration list for PBXProject "ios-deploy" */ = { 558 | isa = XCConfigurationList; 559 | buildConfigurations = ( 560 | 7E7089931B587BF3004D23AA /* Debug */, 561 | 7E7089941B587BF3004D23AA /* Release */, 562 | ); 563 | defaultConfigurationIsVisible = 0; 564 | defaultConfigurationName = Release; 565 | }; 566 | 7E7089951B587BF3004D23AA /* Build configuration list for PBXNativeTarget "ios-deploy" */ = { 567 | isa = XCConfigurationList; 568 | buildConfigurations = ( 569 | 7E7089961B587BF3004D23AA /* Debug */, 570 | 7E7089971B587BF3004D23AA /* Release */, 571 | ); 572 | defaultConfigurationIsVisible = 0; 573 | defaultConfigurationName = Release; 574 | }; 575 | 7E8E3A8A1C45D4CE0017F6C1 /* Build configuration list for PBXNativeTarget "ios-deploy-tests" */ = { 576 | isa = XCConfigurationList; 577 | buildConfigurations = ( 578 | 7E8E3A881C45D4CE0017F6C1 /* Debug */, 579 | 7E8E3A891C45D4CE0017F6C1 /* Release */, 580 | ); 581 | defaultConfigurationIsVisible = 0; 582 | defaultConfigurationName = Release; 583 | }; 584 | 7E8E3A951C45D5380017F6C1 /* Build configuration list for PBXNativeTarget "ios-deploy-lib" */ = { 585 | isa = XCConfigurationList; 586 | buildConfigurations = ( 587 | 7E8E3A961C45D5380017F6C1 /* Debug */, 588 | 7E8E3A971C45D5380017F6C1 /* Release */, 589 | ); 590 | defaultConfigurationIsVisible = 0; 591 | defaultConfigurationName = Release; 592 | }; 593 | /* End XCConfigurationList section */ 594 | }; 595 | rootObject = 7E7089861B587BF3004D23AA /* Project object */; 596 | } 597 | -------------------------------------------------------------------------------- /src/ios-deploy/errors.h: -------------------------------------------------------------------------------- 1 | 2 | typedef struct errorcode_to_id { 3 | unsigned int error; 4 | const char* id; 5 | } errorcode_to_id_t; 6 | 7 | typedef struct error_id_to_message { 8 | const char* id; 9 | const char* message; 10 | } error_id_to_message_t; 11 | 12 | // Parts of error code to localization id map is taken from SDMMobileDevice framework. Associated license is bellow. 13 | // https://github.com/samdmarshall/SDMMobileDevice/blob/master/Framework/MobileDevice/Error/SDMMD_Error.h 14 | // 15 | // Copyright (c) 2014, Sam Marshall 16 | // All rights reserved. 17 | // 18 | // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 19 | // following conditions are met: 20 | // 21 | // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 22 | // 23 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 24 | // in the documentation and/or other materials provided with the distribution. 25 | // 26 | // 3. Neither the name of Sam Marshall nor the names of its contributors may be used to endorse or promote products derived from this 27 | // software without specific prior written permission. 28 | // 29 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 31 | // COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | static errorcode_to_id_t errorcode_to_id[] = { 36 | { 0x00000000, "kAMDSuccess" }, 37 | { 0xe8000001, "kAMDUndefinedError" }, 38 | { 0xe8000002, "kAMDBadHeaderError" }, 39 | { 0xe8000003, "kAMDNoResourcesError" }, 40 | { 0xe8000004, "kAMDReadError" }, 41 | { 0xe8000005, "kAMDWriteError" }, 42 | { 0xe8000006, "kAMDUnknownPacketError" }, 43 | { 0xe8000007, "kAMDInvalidArgumentError" }, 44 | { 0xe8000008, "kAMDNotFoundError" }, 45 | { 0xe8000009, "kAMDIsDirectoryError" }, 46 | { 0xe800000a, "kAMDPermissionError" }, 47 | { 0xe800000b, "kAMDNotConnectedError" }, 48 | { 0xe800000c, "kAMDTimeOutError" }, 49 | { 0xe800000d, "kAMDOverrunError" }, 50 | { 0xe800000e, "kAMDEOFError" }, 51 | { 0xe800000f, "kAMDUnsupportedError" }, 52 | { 0xe8000010, "kAMDFileExistsError" }, 53 | { 0xe8000011, "kAMDBusyError" }, 54 | { 0xe8000012, "kAMDCryptoError" }, 55 | { 0xe8000013, "kAMDInvalidResponseError" }, 56 | { 0xe8000014, "kAMDMissingKeyError" }, 57 | { 0xe8000015, "kAMDMissingValueError" }, 58 | { 0xe8000016, "kAMDGetProhibitedError" }, 59 | { 0xe8000017, "kAMDSetProhibitedError" }, 60 | { 0xe8000018, "kAMDRemoveProhibitedError" }, 61 | { 0xe8000019, "kAMDImmutableValueError" }, 62 | { 0xe800001a, "kAMDPasswordProtectedError" }, 63 | { 0xe800001b, "kAMDMissingHostIDError" }, 64 | { 0xe800001c, "kAMDInvalidHostIDError" }, 65 | { 0xe800001d, "kAMDSessionActiveError" }, 66 | { 0xe800001e, "kAMDSessionInactiveError" }, 67 | { 0xe800001f, "kAMDMissingSessionIDError" }, 68 | { 0xe8000020, "kAMDInvalidSessionIDError" }, 69 | { 0xe8000021, "kAMDMissingServiceError" }, 70 | { 0xe8000022, "kAMDInvalidServiceError" }, 71 | { 0xe8000023, "kAMDInvalidCheckinError" }, 72 | { 0xe8000024, "kAMDCheckinTimeoutError" }, 73 | { 0xe8000025, "kAMDMissingPairRecordError" }, 74 | { 0xe8000026, "kAMDInvalidActivationRecordError" }, 75 | { 0xe8000027, "kAMDMissingActivationRecordError" }, 76 | { 0xe8000028, "kAMDWrongDroidError" }, 77 | { 0xe8000029, "kAMDSUVerificationError" }, 78 | { 0xe800002a, "kAMDSUPatchError" }, 79 | { 0xe800002b, "kAMDSUFirmwareError" }, 80 | { 0xe800002c, "kAMDProvisioningProfileNotValid" }, 81 | { 0xe800002d, "kAMDSendMessageError" }, 82 | { 0xe800002e, "kAMDReceiveMessageError" }, 83 | { 0xe800002f, "kAMDMissingOptionsError" }, 84 | { 0xe8000030, "kAMDMissingImageTypeError" }, 85 | { 0xe8000031, "kAMDDigestFailedError" }, 86 | { 0xe8000032, "kAMDStartServiceError" }, 87 | { 0xe8000033, "kAMDInvalidDiskImageError" }, 88 | { 0xe8000034, "kAMDMissingDigestError" }, 89 | { 0xe8000035, "kAMDMuxError" }, 90 | { 0xe8000036, "kAMDApplicationAlreadyInstalledError" }, 91 | { 0xe8000037, "kAMDApplicationMoveFailedError" }, 92 | { 0xe8000038, "kAMDApplicationSINFCaptureFailedError" }, 93 | { 0xe8000039, "kAMDApplicationSandboxFailedError" }, 94 | { 0xe800003a, "kAMDApplicationVerificationFailedError" }, 95 | { 0xe800003b, "kAMDArchiveDestructionFailedError" }, 96 | { 0xe800003c, "kAMDBundleVerificationFailedError" }, 97 | { 0xe800003d, "kAMDCarrierBundleCopyFailedError" }, 98 | { 0xe800003e, "kAMDCarrierBundleDirectoryCreationFailedError" }, 99 | { 0xe800003f, "kAMDCarrierBundleMissingSupportedSIMsError" }, 100 | { 0xe8000040, "kAMDCommCenterNotificationFailedError" }, 101 | { 0xe8000041, "kAMDContainerCreationFailedError" }, 102 | { 0xe8000042, "kAMDContainerP0wnFailedError" }, 103 | { 0xe8000043, "kAMDContainerRemovalFailedError" }, 104 | { 0xe8000044, "kAMDEmbeddedProfileInstallFailedError" }, 105 | { 0xe8000045, "kAMDErrorError" }, 106 | { 0xe8000046, "kAMDExecutableTwiddleFailedError" }, 107 | { 0xe8000047, "kAMDExistenceCheckFailedError" }, 108 | { 0xe8000048, "kAMDInstallMapUpdateFailedError" }, 109 | { 0xe8000049, "kAMDManifestCaptureFailedError" }, 110 | { 0xe800004a, "kAMDMapGenerationFailedError" }, 111 | { 0xe800004b, "kAMDMissingBundleExecutableError" }, 112 | { 0xe800004c, "kAMDMissingBundleIdentifierError" }, 113 | { 0xe800004d, "kAMDMissingBundlePathError" }, 114 | { 0xe800004e, "kAMDMissingContainerError" }, 115 | { 0xe800004f, "kAMDNotificationFailedError" }, 116 | { 0xe8000050, "kAMDPackageExtractionFailedError" }, 117 | { 0xe8000051, "kAMDPackageInspectionFailedError" }, 118 | { 0xe8000052, "kAMDPackageMoveFailedError" }, 119 | { 0xe8000053, "kAMDPathConversionFailedError" }, 120 | { 0xe8000054, "kAMDRestoreContainerFailedError" }, 121 | { 0xe8000055, "kAMDSeatbeltProfileRemovalFailedError" }, 122 | { 0xe8000056, "kAMDStageCreationFailedError" }, 123 | { 0xe8000057, "kAMDSymlinkFailedError" }, 124 | { 0xe8000058, "kAMDiTunesArtworkCaptureFailedError" }, 125 | { 0xe8000059, "kAMDiTunesMetadataCaptureFailedError" }, 126 | { 0xe800005a, "kAMDAlreadyArchivedError" }, 127 | { 0xe800005b, "kAMDServiceLimitError" }, 128 | { 0xe800005c, "kAMDInvalidPairRecordError" }, 129 | { 0xe800005d, "kAMDServiceProhibitedError" }, 130 | { 0xe800005e, "kAMDCheckinSetupFailedError" }, 131 | { 0xe800005f, "kAMDCheckinConnectionFailedError" }, 132 | { 0xe8000060, "kAMDCheckinReceiveFailedError" }, 133 | { 0xe8000061, "kAMDCheckinResponseFailedError" }, 134 | { 0xe8000062, "kAMDCheckinSendFailedError" }, 135 | { 0xe8000063, "kAMDMuxCreateListenerError" }, 136 | { 0xe8000064, "kAMDMuxGetListenerError" }, 137 | { 0xe8000065, "kAMDMuxConnectError" }, 138 | { 0xe8000066, "kAMDUnknownCommandError" }, 139 | { 0xe8000067, "kAMDAPIInternalError" }, 140 | { 0xe8000068, "kAMDSavePairRecordFailedError" }, 141 | { 0xe8000069, "kAMDCheckinOutOfMemoryError" }, 142 | { 0xe800006a, "kAMDDeviceTooNewError" }, 143 | { 0xe800006b, "kAMDDeviceRefNoGood" }, 144 | { 0xe800006c, "kAMDCannotTranslateError" }, 145 | { 0xe800006d, "kAMDMobileImageMounterMissingImageSignature" }, 146 | { 0xe800006e, "kAMDMobileImageMounterResponseCreationFailed" }, 147 | { 0xe800006f, "kAMDMobileImageMounterMissingImageType" }, 148 | { 0xe8000070, "kAMDMobileImageMounterMissingImagePath" }, 149 | { 0xe8000071, "kAMDMobileImageMounterImageMapLoadFailed" }, 150 | { 0xe8000072, "kAMDMobileImageMounterAlreadyMounted" }, 151 | { 0xe8000073, "kAMDMobileImageMounterImageMoveFailed" }, 152 | { 0xe8000074, "kAMDMobileImageMounterMountPathMissing" }, 153 | { 0xe8000075, "kAMDMobileImageMounterMountPathNotEmpty" }, 154 | { 0xe8000076, "kAMDMobileImageMounterImageMountFailed" }, 155 | { 0xe8000077, "kAMDMobileImageMounterTrustCacheLoadFailed" }, 156 | { 0xe8000078, "kAMDMobileImageMounterDigestFailed" }, 157 | { 0xe8000079, "kAMDMobileImageMounterDigestCreationFailed" }, 158 | { 0xe800007a, "kAMDMobileImageMounterImageVerificationFailed" }, 159 | { 0xe800007b, "kAMDMobileImageMounterImageInfoCreationFailed" }, 160 | { 0xe800007c, "kAMDMobileImageMounterImageMapStoreFailed" }, 161 | { 0xe800007d, "kAMDBonjourSetupError" }, 162 | { 0xe800007e, "kAMDDeviceOSVersionTooLow" }, 163 | { 0xe800007f, "kAMDNoWifiSyncSupportError" }, 164 | { 0xe8000080, "kAMDDeviceFamilyNotSupported" }, 165 | { 0xe8000081, "kAMDEscrowLockedError" }, 166 | { 0xe8000082, "kAMDPairingProhibitedError" }, 167 | { 0xe8000083, "kAMDProhibitedBySupervision" }, 168 | { 0xe8000084, "kAMDDeviceDisconnectedError" }, 169 | { 0xe8000085, "kAMDTooBigError" }, 170 | { 0xe8000086, "kAMDPackagePatchFailedError" }, 171 | { 0xe8000087, "kAMDIncorrectArchitectureError" }, 172 | { 0xe8000088, "kAMDPluginCopyFailedError" }, 173 | { 0xe8000089, "kAMDBreadcrumbFailedError" }, 174 | { 0xe800008a, "kAMDBreadcrumbUnlockError" }, 175 | { 0xe800008b, "kAMDGeoJSONCaptureFailedError" }, 176 | { 0xe800008c, "kAMDNewsstandArtworkCaptureFailedError" }, 177 | { 0xe800008d, "kAMDMissingCommandError" }, 178 | { 0xe800008e, "kAMDNotEntitledError" }, 179 | { 0xe800008f, "kAMDMissingPackagePathError" }, 180 | { 0xe8000090, "kAMDMissingContainerPathError" }, 181 | { 0xe8000091, "kAMDMissingApplicationIdentifierError" }, 182 | { 0xe8000092, "kAMDMissingAttributeValueError" }, 183 | { 0xe8000093, "kAMDLookupFailedError" }, 184 | { 0xe8000094, "kAMDDictCreationFailedError" }, 185 | { 0xe8000095, "kAMDUserDeniedPairingError" }, 186 | { 0xe8000096, "kAMDPairingDialogResponsePendingError" }, 187 | { 0xe8000097, "kAMDInstallProhibitedError" }, 188 | { 0xe8000098, "kAMDUninstallProhibitedError" }, 189 | { 0xe8000099, "kAMDFMiPProtectedError" }, 190 | { 0xe800009a, "kAMDMCProtected" }, 191 | { 0xe800009b, "kAMDMCChallengeRequired" }, 192 | { 0xe800009c, "kAMDMissingBundleVersionError" }, 193 | { 0xe800009d, "kAMDAppBlacklistedError" }, 194 | { 0xe800009e, "This app contains an app extension with an illegal bundle identifier. App extension bundle identifiers must have a prefix consisting of their containing application's bundle identifier followed by a '.'." }, 195 | { 0xe800009f, "If an app extension defines the XPCService key in its Info.plist, it must have a dictionary value." }, 196 | { 0xe80000a0, "App extensions must define the NSExtension key with a dictionary value in their Info.plist." }, 197 | { 0xe80000a1, "If an app extension defines the CFBundlePackageType key in its Info.plist, it must have the value \"XPC!\"." }, 198 | { 0xe80000a2, "App extensions must define either NSExtensionMainStoryboard or NSExtensionPrincipalClass keys in the NSExtension dictionary in their Info.plist." }, 199 | { 0xe80000a3, "If an app extension defines the NSExtensionContextClass key in the NSExtension dictionary in its Info.plist, it must have a string value containing one or more characters." }, 200 | { 0xe80000a4, "If an app extension defines the NSExtensionContextHostClass key in the NSExtension dictionary in its Info.plist, it must have a string value containing one or more characters." }, 201 | { 0xe80000a5, "If an app extension defines the NSExtensionViewControllerHostClass key in the NSExtension dictionary in its Info.plist, it must have a string value containing one or more characters." }, 202 | { 0xe80000a6, "This app contains an app extension that does not define the NSExtensionPointIdentifier key in its Info.plist. This key must have a reverse-DNS format string value." }, 203 | { 0xe80000a7, "This app contains an app extension that does not define the NSExtensionPointIdentifier key in its Info.plist with a valid reverse-DNS format string value." }, 204 | { 0xe80000a8, "If an app extension defines the NSExtensionAttributes key in the NSExtension dictionary in its Info.plist, it must have a dictionary value." }, 205 | { 0xe80000a9, "If an app extension defines the NSExtensionPointName key in the NSExtensionAttributes dictionary in the NSExtension dictionary in its Info.plist, it must have a string value containing one or more characters." }, 206 | { 0xe80000aa, "If an app extension defines the NSExtensionPointVersion key in the NSExtensionAttributes dictionary in the NSExtension dictionary in its Info.plist, it must have a string value containing one or more characters." }, 207 | { 0xe80000ab, "This app or a bundle it contains does not define the CFBundleName key in its Info.plist with a string value containing one or more characters." }, 208 | { 0xe80000ac, "This app or a bundle it contains does not define the CFBundleDisplayName key in its Info.plist with a string value containing one or more characters." }, 209 | { 0xe80000ad, "This app or a bundle it contains defines the CFBundleShortVersionStringKey key in its Info.plist with a non-string value or a zero-length string value." }, 210 | { 0xe80000ae, "This app or a bundle it contains defines the RunLoopType key in the XPCService dictionary in its Info.plist with a non-string value or a zero-length string value." }, 211 | { 0xe80000af, "This app or a bundle it contains defines the ServiceType key in the XPCService dictionary in its Info.plist with a non-string value or a zero-length string value." }, 212 | { 0xe80000b0, "This application or a bundle it contains has the same bundle identifier as this application or another bundle that it contains. Bundle identifiers must be unique." }, 213 | { 0xe80000b1, "This app contains an app extension that specifies an extension point identifier that is not supported on this version of iOS for the value of the NSExtensionPointIdentifier key in its Info.plist." }, 214 | { 0xe80000b2, "This app contains multiple app extensions that are file providers. Apps are only allowed to contain at most a single file provider app extension." }, 215 | { 0xe80000b3, "kMobileHouseArrestMissingCommand" }, 216 | { 0xe80000b4, "kMobileHouseArrestUnknownCommand" }, 217 | { 0xe80000b5, "kMobileHouseArrestMissingIdentifier" }, 218 | { 0xe80000b6, "kMobileHouseArrestDictionaryFailed" }, 219 | { 0xe80000b7, "kMobileHouseArrestInstallationLookupFailed" }, 220 | { 0xe80000b8, "kMobileHouseArrestApplicationLookupFailed" }, 221 | { 0xe80000b9, "kMobileHouseArrestMissingContainer" }, 222 | // 0xe80000ba does not exist 223 | { 0xe80000bb, "kMobileHouseArrestPathConversionFailed" }, 224 | { 0xe80000bc, "kMobileHouseArrestPathMissing" }, 225 | { 0xe80000bd, "kMobileHouseArrestInvalidPath" }, 226 | { 0xe80000be, "kAMDMismatchedApplicationIdentifierEntitlementError" }, 227 | { 0xe80000bf, "kAMDInvalidSymlinkError" }, 228 | { 0xe80000c0, "kAMDNoSpaceError" }, 229 | { 0xe80000c1, "The WatchKit app extension must have, in its Info.plist's NSExtension dictionary's NSExtensionAttributes dictionary, the key WKAppBundleIdentifier with a value equal to the associated WatchKit app's bundle identifier." }, 230 | { 0xe80000c2, "This app is not a valid AppleTV Stub App" }, 231 | { 0xe80000c3, "kAMDBundleiTunesMetadataVersionMismatchError" }, 232 | { 0xe80000c4, "kAMDInvalidiTunesMetadataPlistError" }, 233 | { 0xe80000c5, "kAMDMismatchedBundleIDSigningIdentifierError" }, 234 | { 0xe80000c6, "This app contains multiple WatchKit app extensions. Only a single WatchKit extension is allowed." }, 235 | { 0xe80000c7, "A WatchKit app within this app is not a valid bundle." }, 236 | { 0xe80000c8, "kAMDDeviceNotSupportedByThinningError" }, 237 | { 0xe80000c9, "The UISupportedDevices key in this app's Info.plist does not specify a valid set of supported devices." }, 238 | { 0xe80000ca, "This app contains an app extension with an illegal bundle identifier. App extension bundle identifiers must have a prefix consisting of their containing application's bundle identifier followed by a '.', with no further '.' characters after the prefix." }, 239 | { 0xe80000cb, "kAMDAppexBundleIDConflictWithOtherIdentifierError" }, 240 | { 0xe80000cc, "kAMDBundleIDConflictWithOtherIdentifierError" }, 241 | { 0xe80000cd, "This app contains multiple WatchKit 1.0 apps. Only a single WatchKit 1.0 app is allowed." }, 242 | { 0xe80000ce, "This app contains multiple WatchKit 2.0 apps. Only a single WatchKit 2.0 app is allowed." }, 243 | { 0xe80000cf, "The WatchKit app has an invalid stub executable." }, 244 | { 0xe80000d0, "The WatchKit app has multiple app extensions. Only a single WatchKit extension is allowed in a WatchKit app, and only if this is a WatchKit 2.0 app." }, 245 | { 0xe80000d1, "The WatchKit 2.0 app contains non-WatchKit app extensions. Only WatchKit app extensions are allowed in WatchKit apps." }, 246 | { 0xe80000d2, "The WatchKit app has one or more embedded frameworks. Frameworks are only allowed in WatchKit app extensions in WatchKit 2.0 apps." }, 247 | { 0xe80000d3, "This app contains a WatchKit 1.0 app with app extensions. This is not allowed." }, 248 | { 0xe80000d4, "This app contains a WatchKit 2.0 app without an app extension. WatchKit 2.0 apps must contain a WatchKit app extension." }, 249 | { 0xe80000d5, "The WatchKit app's Info.plist must have a WKCompanionAppBundleIdentifier key set to the bundle identifier of the companion app." }, 250 | { 0xe80000d6, "The WatchKit app's Info.plist contains a non-string key." }, 251 | { 0xe80000d7, "The WatchKit app's Info.plist contains a key that is not in the whitelist of allowed keys for a WatchKit app." }, 252 | { 0xe80000d8, "The WatchKit 1.0 and a WatchKit 2.0 apps within this app must have have the same bundle identifier." }, 253 | { 0xe80000d9, "This app contains a WatchKit app with an invalid bundle identifier. The bundle identifier of a WatchKit app must have a prefix consisting of the companion app's bundle identifier, followed by a '.'." }, 254 | { 0xe80000da, "This app contains a WatchKit app where the UIDeviceFamily key in its Info.plist does not specify the value 4 to indicate that it's compatible with the Apple Watch device type." }, 255 | { 0xe80000db, "The device is out of storage for apps. Please remove some apps from the device and try again." }, 256 | { 0xe80000dc, "This app or an app that it contains has a Siri Intents app extension that is missing the IntentsSupported array in the NSExtensionAttributes dictionary in the NSExtension dictionary in its Info.plist." }, 257 | { 0xe80000dd, "This app or an app that it contains has a Siri Intents app extension that does not correctly define the IntentsRestrictedWhileLocked key in the NSExtensionAttributes dictionary in the NSExtension dictionary in its Info.plist. The key's value must be an array of strings." }, 258 | { 0xe80000de, "This app or an app that it contains has a Siri Intents app extension that declares values in its IntentsRestrictedWhileLocked key's array value that are not in its IntentsSupported key's array value (in the NSExtensionAttributes dictionary in the NSExtension dictionary in its Info.plist)." }, 259 | { 0xe80000df, "This app or an app that it contains declares multiple Siri Intents app extensions that declare one or more of the same values in the IntentsSupported array in the NSExtensionAttributes dictionary in the NSExtension dictionary in their Info.plist. IntentsSupported must be distinct among a given Siri Intents extension type within an app." }, 260 | { 0xe80000e0, "The WatchKit 2.0 app, which expects to be compatible with watchOS versions earlier than 3.0, contains a non-WatchKit extension in a location that's not compatible with watchOS versions earlier than 3.0." }, 261 | { 0xe80000e1, "The WatchKit 2.0 app, which expects to be compatible with watchOS versions earlier than 3.0, contains a framework in a location that's not compatible with watchOS versions earlier than 3.0." }, 262 | { 0xe80000e2, "kAMDMobileImageMounterDeviceLocked" }, 263 | { 0xe80000e3, "kAMDInvalidSINFError" }, 264 | { 0xe80000e4, "Multiple iMessage app extensions were found in this app. Only one is allowed." }, 265 | { 0xe80000e5, "This iMessage application is missing its required iMessage app extension." }, 266 | { 0xe80000e6, "This iMessage application contains an app extension type other than an iMessage app extension. iMessage applications may only contain one iMessage app extension and may not contain other types of app extensions." }, 267 | { 0xe80000e7, "This app contains a WatchKit app with one or more Siri Intents app extensions that declare IntentsSupported that are not declared in any of the companion app's Siri Intents app extensions. WatchKit Siri Intents extensions' IntentsSupported values must be a subset of the companion app's Siri Intents extensions' IntentsSupported values." }, 268 | { 0xe80000e8, "kAMDRequireCUPairingCodeError" }, 269 | { 0xe80000e9, "kAMDRequireCUPairingBackoffError" }, 270 | { 0xe80000ea, "kAMDCUPairingError" }, 271 | { 0xe80000eb, "kAMDCUPairingContinueError" }, 272 | { 0xe80000ec, "kAMDCUPairingResetError" }, 273 | { 0xe80000ed, "kAMDRequireCUPairingError" }, 274 | { 0xe80000ee, "kAMDPasswordRequiredError" }, 275 | 276 | // Errors without id->string mapping. 277 | { 0xe8008001, "An unknown error has occurred." }, 278 | { 0xe8008002, "Attempted to modify an immutable provisioning profile." }, 279 | { 0xe8008003, "This provisioning profile is malformed." }, 280 | { 0xe8008004, "This provisioning profile does not have a valid signature (or it has a valid, but untrusted signature)." }, 281 | { 0xe8008005, "This provisioning profile is malformed." }, 282 | { 0xe8008006, "This provisioning profile is malformed." }, 283 | { 0xe8008007, "This provisioning profile is malformed." }, 284 | { 0xe8008008, "This provisioning profile is malformed." }, 285 | { 0xe8008009, "The signature was not valid." }, 286 | { 0xe800800a, "Unable to allocate memory." }, 287 | { 0xe800800b, "A file operation failed." }, 288 | { 0xe800800c, "There was an error communicating with your device." }, 289 | { 0xe800800d, "There was an error communicating with your device." }, 290 | { 0xe800800e, "This provisioning profile does not have a valid signature (or it has a valid, but untrusted signature)." }, 291 | { 0xe800800f, "The application's signature is valid but it does not match the expected hash." }, 292 | { 0xe8008010, "This provisioning profile is unsupported." }, 293 | { 0xe8008011, "This provisioning profile has expired." }, 294 | { 0xe8008012, "This provisioning profile cannot be installed on this device." }, 295 | { 0xe8008013, "This provisioning profile does not have a valid signature (or it has a valid, but untrusted signature)." }, 296 | { 0xe8008014, "The executable contains an invalid signature." }, 297 | { 0xe8008015, "A valid provisioning profile for this executable was not found." }, 298 | { 0xe8008016, "The executable was signed with invalid entitlements." }, 299 | { 0xe8008017, "A signed resource has been added, modified, or deleted." }, 300 | { 0xe8008018, "The identity used to sign the executable is no longer valid." }, 301 | { 0xe8008019, "The application does not have a valid signature." }, 302 | { 0xe800801a, "This provisioning profile does not have a valid signature (or it has a valid, but untrusted signature)." }, 303 | { 0xe800801b, "There was an error communicating with your device." }, 304 | { 0xe800801c, "No code signature found." }, 305 | { 0xe800801d, "Rejected by policy." }, 306 | { 0xe800801e, "The requested profile does not exist (it may have been removed)." }, 307 | { 0xe800801f, "Attempted to install a Beta profile without the proper entitlement." }, 308 | { 0xe8008020, "Attempted to install a Beta profile over lockdown connection." }, 309 | { 0xe8008021, "The maximum number of apps for free development profiles has been reached." }, 310 | { 0xe8008022, "An error occured while accessing the profile database." }, 311 | { 0xe8008023, "An error occured while communicating with the agent." }, 312 | { 0xe8008024, "The provisioning profile is banned." }, 313 | { 0xe8008025, "The user did not explicitly trust the provisioning profile." }, 314 | { 0xe8008026, "The provisioning profile requires online authorization." }, 315 | { 0xe8008027, "The cdhash is not in the trust cache." }, 316 | { 0xe8008028, "Invalid arguments or option combination." }, 317 | }; 318 | 319 | const int errorcode_to_id_count = sizeof(errorcode_to_id) / sizeof(errorcode_to_id_t); 320 | 321 | // Taken from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/Resources/English.lproj/Localizable.strings 322 | error_id_to_message_t error_id_to_message[] = { 323 | { "kAMDAPIInternalError", "There was an internal API error." }, 324 | { "kAMDAlreadyArchivedError", "The application is already archived." }, 325 | { "kAMDAppBlacklistedError", "This app is not allowed to be installed on this device." }, 326 | { "kAMDAppexBundleIDConflictWithOtherIdentifierError", "This application contains an app extension with a bundle identifier that conflicts with the bundle identifier of another app or app extension already installed." }, 327 | { "kAMDApplicationAlreadyInstalledError", "A system application with the given bundle identifier is already installed on the device and cannot be replaced." }, 328 | { "kAMDApplicationMoveFailedError", "The application could not be moved into place on the device." }, 329 | { "kAMDApplicationSandboxFailedError", "The application could not be sandboxed." }, 330 | { "kAMDApplicationVerificationFailedError", "The application could not be verified." }, 331 | { "kAMDArchiveDestructionFailedError", "Could not remove the application archive." }, 332 | { "kAMDBadHeaderError", "Could not transfer file." }, 333 | { "kAMDBreadcrumbFailedError", "Could not write installation breadcrumb." }, 334 | { "kAMDBreadcrumbUnlockError", "Could not update installation breadcrumb." }, 335 | { "kAMDBundleIDConflictWithOtherIdentifierError", "This application's bundle identifier conflicts with the identifier of another app or app extension already installed." }, 336 | { "kAMDBundleVerificationFailedError", "The carrier bundle could not be verified." }, 337 | { "kAMDBundleiTunesMetadataVersionMismatchError", "This application's iTunesMetadata.plist specifies versions that do not match the versions listed for the app in its Info.plist" }, 338 | { "kAMDBusyError", "The device is busy." }, 339 | { "kAMDCUPairingContinueError", "Continue pairing process over the network." }, 340 | { "kAMDCUPairingError", "General failure while pairing over the network." }, 341 | { "kAMDCUPairingResetError", "Pairing was reset due to earlier issues, try again." }, 342 | { "kAMDCannotTranslateError", "Could not translate messages from device" }, 343 | { "kAMDCarrierBundleCopyFailedError", "Could not install the carrier bundle." }, 344 | { "kAMDCarrierBundleDirectoryCreationFailedError", "Could not create the carrier bundle directory." }, 345 | { "kAMDCarrierBundleMissingSupportedSIMsError", "There are no supported SIMs for this carrier bundle." }, 346 | { "kAMDCheckinConnectionFailedError", "The service did not start properly on the device." }, 347 | { "kAMDCheckinOutOfMemoryError", "The service did not start properly on the device." }, 348 | { "kAMDCheckinReceiveFailedError", "The service did not start properly on the device." }, 349 | { "kAMDCheckinResponseFailedError", "The service did not start properly on the device." }, 350 | { "kAMDCheckinSendFailedError", "The service did not start properly on the device." }, 351 | { "kAMDCheckinSetupFailedError", "Could not start service on device" }, 352 | { "kAMDCheckinTimeoutError", "The service did not start properly on the device." }, 353 | { "kAMDCommCenterNotificationFailedError", "Could not listen for notification from the baseband." }, 354 | { "kAMDContainerCreationFailedError", "Could not create application container." }, 355 | { "kAMDContainerP0wnFailedError", "Could not repair permissions on application container." }, 356 | { "kAMDContainerRemovalFailedError", "Could not remove the application container." }, 357 | { "kAMDCryptoError", "Could not establish a secure connection to the device." }, 358 | { "kAMDDeviceDisconnectedError", "This device is no longer connected." }, 359 | { "kAMDDeviceFamilyNotSupported", "This application does not support this kind of device." }, 360 | { "kAMDDeviceNotSupportedByThinningError", "This application is not built for this device." }, 361 | { "kAMDDeviceOSVersionTooLow", "The device OS version is too low." }, 362 | { "kAMDDeviceRefNoGood", "This device is no longer connected." }, 363 | { "kAMDDeviceTooNewError", "This application needs to be updated." }, 364 | { "kAMDDictCreationFailedError", "Could not extract capabilities from the request." }, 365 | { "kAMDDigestFailedError", "Could not read disk image." }, 366 | { "kAMDEOFError", "End of file." }, 367 | { "kAMDEmbeddedProfileInstallFailedError", "Could not install the embedded provisioning profile." }, 368 | { "kAMDErrorError", "An error occurred." }, 369 | { "kAMDEscrowLockedError", "Device is not available until first unlock after boot." }, 370 | { "kAMDExecutableTwiddleFailedError", "Could not change executable permissions on the application." }, 371 | { "kAMDExistenceCheckFailedError", "Could not check to see if the application already exists." }, 372 | { "kAMDFMiPProtectedError", "The device is in lost mode." }, 373 | { "kAMDFileExistsError", "The file already exists." }, 374 | { "kAMDGeoJSONCaptureFailedError", "Could not save the GeoJSON data." }, 375 | { "kAMDGetProhibitedError", "Cannot retrieve value from the passcode locked device." }, 376 | { "kAMDImmutableValueError", "This value cannot be changed." }, 377 | { "kAMDIncorrectArchitectureError", "This application does not support this device's CPU type." }, 378 | { "kAMDInstallMapUpdateFailedError", "Could not update the installed applications list." }, 379 | { "kAMDInstallProhibitedError", "Installation of apps is prohibited by a policy on the device." }, 380 | { "kAMDInvalidActivationRecordError", "The activation record is not valid." }, 381 | { "kAMDInvalidArgumentError", "The argument is invalid." }, 382 | { "kAMDInvalidCheckinError", "Could not start service on device" }, 383 | { "kAMDInvalidDiskImageError", "The disk image is invalid." }, 384 | { "kAMDInvalidHostIDError", "The device does not recognize this host." }, 385 | { "kAMDInvalidPairRecordError", "The host is no longer paired with the device." }, 386 | { "kAMDInvalidResponseError", "Received an unexpected response from the device." }, 387 | { "kAMDInvalidSINFError", "The encryption information included with this application is not valid so this application cannot be installed on this device." }, 388 | { "kAMDInvalidServiceError", "The service is invalid." }, 389 | { "kAMDInvalidSessionIDError", "The session ID is invalid." }, 390 | { "kAMDInvalidSymlinkError", "The bundle contained an invalid symlink." }, 391 | { "kAMDInvalidiTunesMetadataPlistError", "This application's iTunesMetadata.plist is not valid." }, 392 | { "kAMDIsDirectoryError", "The path is a directory." }, 393 | { "kAMDLookupFailedError", "Could not list installed applications." }, 394 | { "kAMDMCChallengeRequired", "A policy on the device requires secure pairing." }, 395 | { "kAMDMCProtected", "Pairing is prohibited by a policy on the device." }, 396 | { "kAMDManifestCaptureFailedError", "Could not save the application manifest." }, 397 | { "kAMDMapGenerationFailedError", "Could not generate the map." }, 398 | { "kAMDMismatchedApplicationIdentifierEntitlementError", "This application's application-identifier entitlement does not match that of the installed application. These values must match for an upgrade to be allowed." }, 399 | { "kAMDMismatchedBundleIDSigningIdentifierError", "This application's bundle identifier does not match its code signing identifier." }, 400 | { "kAMDMissingActivationRecordError", "The activation record could not be found." }, 401 | { "kAMDMissingApplicationIdentifierError", "Request was missing the application identifier." }, 402 | { "kAMDMissingAttributeValueError", "Request was missing a required value." }, 403 | { "kAMDMissingBundleExecutableError", "The application bundle does not contain an executable." }, 404 | { "kAMDMissingBundleIdentifierError", "The application bundle does not contain a valid identifier." }, 405 | { "kAMDMissingBundlePathError", "Could not determine the application bundle path." }, 406 | { "kAMDMissingBundleVersionError", "The bundle's Info.plist does not contain a CFBundleVersion key or its value is not a string." }, 407 | { "kAMDMissingCommandError", "The request did not contain a command." }, 408 | { "kAMDMissingContainerError", "Could not find the container for the installed application." }, 409 | { "kAMDMissingContainerPathError", "Request was missing the container path." }, 410 | { "kAMDMissingDigestError", "The digest is missing." }, 411 | { "kAMDMissingHostIDError", "The device does not recognize this host." }, 412 | { "kAMDMissingImageTypeError", "The image is missing." }, 413 | { "kAMDMissingKeyError", "The key is missing." }, 414 | { "kAMDMissingOptionsError", "The options are missing." }, 415 | { "kAMDMissingPackagePathError", "Request was missing the package path." }, 416 | { "kAMDMissingPairRecordError", "The host is not paired with the device." }, 417 | { "kAMDMissingServiceError", "The service is missing." }, 418 | { "kAMDMissingSessionIDError", "The session ID is missing." }, 419 | { "kAMDMissingValueError", "The value is missing." }, 420 | { "kAMDMobileImageMounterAlreadyMounted", "Image is already mounted." }, 421 | { "kAMDMobileImageMounterDeviceLocked", "The device is locked." }, 422 | { "kAMDMobileImageMounterDigestCreationFailed", "Could not support development." }, 423 | { "kAMDMobileImageMounterDigestFailed", "Could not support development." }, 424 | { "kAMDMobileImageMounterImageInfoCreationFailed", "Could not support development." }, 425 | { "kAMDMobileImageMounterImageMapLoadFailed", "Could not support development." }, 426 | { "kAMDMobileImageMounterImageMapStoreFailed", "Could not support development." }, 427 | { "kAMDMobileImageMounterImageMountFailed", "Could not support development." }, 428 | { "kAMDMobileImageMounterImageMoveFailed", "Could not support development." }, 429 | { "kAMDMobileImageMounterImageVerificationFailed", "Could not support development." }, 430 | { "kAMDMobileImageMounterMissingImagePath", "Could not support development." }, 431 | { "kAMDMobileImageMounterMissingImageSignature", "Could not support development." }, 432 | { "kAMDMobileImageMounterMissingImageType", "Could not support development." }, 433 | { "kAMDMobileImageMounterMountPathMissing", "Could not support development." }, 434 | { "kAMDMobileImageMounterMountPathNotEmpty", "Could not support development." }, 435 | { "kAMDMobileImageMounterResponseCreationFailed", "Could not support development." }, 436 | { "kAMDMobileImageMounterTrustCacheLoadFailed", "Could not support development." }, 437 | { "kAMDMuxConnectError", "Could not connect to the device." }, 438 | { "kAMDMuxCreateListenerError", "Could not listen for USB devices." }, 439 | { "kAMDMuxError", "There was an error with the USB device multiplexor." }, 440 | { "kAMDMuxGetListenerError", "Could not get the USB listener." }, 441 | { "kAMDNewsstandArtworkCaptureFailedError", "Could not save the Newsstand artwork." }, 442 | { "kAMDNoResourcesError", "Could not allocate a resource." }, 443 | { "kAMDNoSpaceError", "No space is available on the device." }, 444 | { "kAMDNoWifiSyncSupportError", "Device doesn't support wireless sync." }, 445 | { "kAMDNotConnectedError", "Not connected to the device." }, 446 | { "kAMDNotEntitledError", "The requesting application is not allowed to make this request." }, 447 | { "kAMDNotFoundError", "The file could not be found." }, 448 | { "kAMDNotificationFailedError", "Could not post a notification." }, 449 | { "kAMDOverrunError", "There was a buffer overrun." }, 450 | { "kAMDPackageExtractionFailedError", "Could not open the application package." }, 451 | { "kAMDPackageInspectionFailedError", "Could not inspect the application package." }, 452 | { "kAMDPackageMoveFailedError", "Could not move the application package into the staging location." }, 453 | { "kAMDPackagePatchFailedError", "Could not apply patch update to application." }, 454 | { "kAMDPairingDialogResponsePendingError", "The user has not yet responded to the pairing request." }, 455 | { "kAMDPairingProhibitedError", "Pairing only allowed over USB." }, 456 | { "kAMDPasswordProtectedError", "The device is passcode protected." }, 457 | { "kAMDPasswordRequiredError", "A passcode is required to be set on the device." }, 458 | { "kAMDPathConversionFailedError", "Could not convert the path." }, 459 | { "kAMDPermissionError", "You do not have permission." }, 460 | { "kAMDPluginCopyFailedError", "Could not copy VPN Plugin into app container." }, 461 | { "kAMDProhibitedBySupervision", "Operation prohibited on supervised devices." }, 462 | { "kAMDProvisioningProfileNotValid", "The provisioning profile is not valid." }, 463 | { "kAMDReadError", "Could not read from the device." }, 464 | { "kAMDReceiveMessageError", "Could not receive a message from the device." }, 465 | { "kAMDRemoveProhibitedError", "Cannot remove value on device." }, 466 | { "kAMDRequireCUPairingBackoffError", "Retry later." }, 467 | { "kAMDRequireCUPairingCodeError", "Invalid PIN code entered." }, 468 | { "kAMDRequireCUPairingError", "Cannot pair over network yet" }, 469 | { "kAMDRestoreContainerFailedError", "Could not restore the application container." }, 470 | { "kAMDSUFirmwareError", "Could not flash the firmware." }, 471 | { "kAMDSUPatchError", "Could not patch the file." }, 472 | { "kAMDSUVerificationError", "The software update package could not be verified." }, 473 | { "kAMDSavePairRecordFailedError", "Could not save the pairing record." }, 474 | { "kAMDSeatbeltProfileRemovalFailedError", "Could not remove the application seatbelt profile." }, 475 | { "kAMDSendMessageError", "Could not send a message to the device." }, 476 | { "kAMDServiceLimitError", "Too many instances of this service are already running." }, 477 | { "kAMDServiceProhibitedError", "The service could not be started on the device." }, 478 | { "kAMDSessionActiveError", "The session is active." }, 479 | { "kAMDSessionInactiveError", "The session is inactive." }, 480 | { "kAMDSetProhibitedError", "Cannot set value on device." }, 481 | { "kAMDStageCreationFailedError", "Could not create the staging directory." }, 482 | { "kAMDStartServiceError", "The service could not be started." }, 483 | { "kAMDSuccess", "There was no error." }, 484 | { "kAMDSymlinkFailedError", "Could not create the symlink." }, 485 | { "kAMDTimeOutError", "The operation timed out." }, 486 | { "kAMDTooBigError", "The message is too big." }, 487 | { "kAMDUndefinedError", "An unknown error occurred." }, 488 | { "kAMDUninstallProhibitedError", "Uninstallation of apps is prohibited by a policy on the device." }, 489 | { "kAMDUnknownCommandError", "The device does not recognize the command." }, 490 | { "kAMDUnknownPacketError", "The packet is unknown." }, 491 | { "kAMDUnsupportedError", "This operation is unsupported." }, 492 | { "kAMDUserDeniedPairingError", "The device rejected the pairing attempt." }, 493 | { "kAMDWriteError", "Could not write to the device." }, 494 | { "kAMDWrongDroidError", "The device is in recovery mode." }, 495 | { "kAMDiTunesArtworkCaptureFailedError", "Could not save the iTunes artwork." }, 496 | { "kAMDiTunesMetadataCaptureFailedError", "Could not save the iTunes metadata." }, 497 | { "kMobileHouseArrestApplicationLookupFailed", "The requested application is not a user application." }, 498 | { "kMobileHouseArrestDictionaryFailed", "The request contained an invalid request dictionary." }, 499 | { "kMobileHouseArrestInstallationLookupFailed", "Could not find the requested application." }, 500 | { "kMobileHouseArrestInvalidPath", "The requested application contained an invalid data container path." }, 501 | { "kMobileHouseArrestMissingCommand", "The request was missing a command." }, 502 | { "kMobileHouseArrestMissingContainer", "The requested application does not contain a valid data container." }, 503 | { "kMobileHouseArrestMissingIdentifier", "The request was missing an application identifier." }, 504 | { "kMobileHouseArrestPathConversionFailed", "Could not convert the requested application's data container path." }, 505 | { "kMobileHouseArrestPathMissing", "The requested application's data container path does not exist." }, 506 | { "kMobileHouseArrestUnknownCommand", "The request contained an invalid command." }, 507 | }; 508 | 509 | const int error_id_to_message_count = sizeof(error_id_to_message) / sizeof(error_id_to_message_t); 510 | 511 | const char* get_error_message(unsigned int error) { 512 | const char* id = NULL; 513 | 514 | // Lookup error localization id 515 | for (int i = 0; i < errorcode_to_id_count; i++) { 516 | if (errorcode_to_id[i].error == error) { 517 | id = errorcode_to_id[i].id; 518 | break; 519 | } 520 | } 521 | 522 | // Lookup error message 523 | if (id) { 524 | for (int i = 0; i < error_id_to_message_count; i++) 525 | if (strcmp(error_id_to_message[i].id, id) == 0) 526 | return error_id_to_message[i].message; 527 | } 528 | 529 | // If message is not found, then at least return id if it was found, otherwise NULL 530 | return id; 531 | }; 532 | -------------------------------------------------------------------------------- /src/ios-deploy/ios-deploy.m: -------------------------------------------------------------------------------- 1 | //TODO: don't copy/mount DeveloperDiskImage.dmg if it's already done - Xcode checks this somehow 2 | 3 | #import 4 | #import 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "MobileDevice.h" 19 | #import "errors.h" 20 | #import "device_db.h" 21 | 22 | #define PREP_CMDS_PATH @"/tmp/%@/fruitstrap-lldb-prep-cmds-" 23 | #define LLDB_SHELL @"lldb -s %@" 24 | /* 25 | * Startup script passed to lldb. 26 | * To see how xcode interacts with lldb, put this into .lldbinit: 27 | * log enable -v -f /Users/vargaz/lldb.log lldb all 28 | * log enable -v -f /Users/vargaz/gdb-remote.log gdb-remote all 29 | */ 30 | #define LLDB_PREP_CMDS CFSTR("\ 31 | platform select remote-ios --sysroot '{symbols_path}'\n\ 32 | target create \"{disk_app}\"\n\ 33 | script fruitstrap_device_app=\"{device_app}\"\n\ 34 | script fruitstrap_connect_url=\"connect://127.0.0.1:{device_port}\"\n\ 35 | target modules search-paths add {modules_search_paths_pairs}\n\ 36 | command script import \"{python_file_path}\"\n\ 37 | command script add -f {python_command}.connect_command connect\n\ 38 | command script add -s asynchronous -f {python_command}.run_command run\n\ 39 | command script add -s asynchronous -f {python_command}.autoexit_command autoexit\n\ 40 | command script add -s asynchronous -f {python_command}.safequit_command safequit\n\ 41 | connect\n\ 42 | ") 43 | 44 | const char* lldb_prep_no_cmds = ""; 45 | 46 | const char* lldb_prep_interactive_cmds = "\ 47 | run\n\ 48 | "; 49 | 50 | const char* lldb_prep_noninteractive_justlaunch_cmds = "\ 51 | run\n\ 52 | safequit\n\ 53 | "; 54 | 55 | const char* lldb_prep_noninteractive_cmds = "\ 56 | run\n\ 57 | autoexit\n\ 58 | "; 59 | 60 | /* 61 | * Some things do not seem to work when using the normal commands like process connect/launch, so we invoke them 62 | * through the python interface. Also, Launch () doesn't seem to work when ran from init_module (), so we add 63 | * a command which can be used by the user to run it. 64 | */ 65 | NSString* LLDB_FRUITSTRAP_MODULE = @ 66 | #include "lldb.py.h" 67 | ; 68 | 69 | 70 | typedef struct am_device * AMDeviceRef; 71 | mach_error_t AMDeviceSecureStartService(struct am_device *device, CFStringRef service_name, unsigned int *unknown, service_conn_t *handle); 72 | int AMDeviceSecureTransferPath(int zero, AMDeviceRef device, CFURLRef url, CFDictionaryRef options, void *callback, int cbarg); 73 | int AMDeviceSecureInstallApplication(int zero, AMDeviceRef device, CFURLRef url, CFDictionaryRef options, void *callback, int cbarg); 74 | int AMDeviceMountImage(AMDeviceRef device, CFStringRef image, CFDictionaryRef options, void *callback, int cbarg); 75 | mach_error_t AMDeviceLookupApplications(AMDeviceRef device, CFDictionaryRef options, CFDictionaryRef *result); 76 | int AMDeviceGetInterfaceType(struct am_device *device); 77 | 78 | bool found_device = false, debug = false, verbose = false, unbuffered = false, nostart = false, detect_only = false, install = true, uninstall = false, no_wifi = false; 79 | bool command_only = false; 80 | char *command = NULL; 81 | char const*target_filename = NULL; 82 | char const*upload_pathname = NULL; 83 | char *bundle_id = NULL; 84 | bool interactive = true; 85 | bool justlaunch = false; 86 | char *app_path = NULL; 87 | char *device_id = NULL; 88 | char *args = NULL; 89 | char *list_root = NULL; 90 | int _timeout = 0; 91 | int _detectDeadlockTimeout = 0; 92 | int port = 0; // 0 means "dynamically assigned" 93 | CFStringRef last_path = NULL; 94 | service_conn_t gdbfd; 95 | pid_t parent = 0; 96 | // PID of child process running lldb 97 | pid_t child = 0; 98 | // Signal sent from child to parent process when LLDB finishes. 99 | const int SIGLLDB = SIGUSR1; 100 | AMDeviceRef best_device_match = NULL; 101 | NSString* tmpUUID; 102 | struct am_device_notification *notify; 103 | 104 | // Error codes we report on different failures, so scripts can distinguish between user app exit 105 | // codes and our exit codes. For non app errors we use codes in reserved 128-255 range. 106 | const int exitcode_timeout = 252; 107 | const int exitcode_error = 253; 108 | const int exitcode_app_crash = 254; 109 | 110 | // Checks for MobileDevice.framework errors, tries to print them and exits. 111 | #define check_error(call) \ 112 | do { \ 113 | unsigned int err = (unsigned int)call; \ 114 | if (err != 0) \ 115 | { \ 116 | const char* msg = get_error_message(err); \ 117 | /*on_error("Error 0x%x: %s " #call, err, msg ? msg : "unknown.");*/ \ 118 | on_error(@"Error 0x%x: %@ " #call, err, msg ? [NSString stringWithUTF8String:msg] : @"unknown."); \ 119 | } \ 120 | } while (false); 121 | 122 | void on_error(NSString* format, ...) 123 | { 124 | va_list valist; 125 | va_start(valist, format); 126 | NSString* str = [[[NSString alloc] initWithFormat:format arguments:valist] autorelease]; 127 | va_end(valist); 128 | 129 | NSLog(@"[ !! ] %@", str); 130 | 131 | exit(exitcode_error); 132 | } 133 | 134 | // Print error message getting last errno and exit 135 | void on_sys_error(NSString* format, ...) { 136 | const char* errstr = strerror(errno); 137 | 138 | va_list valist; 139 | va_start(valist, format); 140 | NSString* str = [[[NSString alloc] initWithFormat:format arguments:valist] autorelease]; 141 | va_end(valist); 142 | 143 | on_error(@"%@ : %@", str, [NSString stringWithUTF8String:errstr]); 144 | } 145 | 146 | void __NSLogOut(NSString* format, va_list valist) { 147 | NSString* str = [[[NSString alloc] initWithFormat:format arguments:valist] autorelease]; 148 | [[str stringByAppendingString:@"\n"] writeToFile:@"/dev/stdout" atomically:NO encoding:NSUTF8StringEncoding error:nil]; 149 | } 150 | 151 | void NSLogOut(NSString* format, ...) { 152 | va_list valist; 153 | va_start(valist, format); 154 | __NSLogOut(format, valist); 155 | va_end(valist); 156 | } 157 | 158 | void NSLogVerbose(NSString* format, ...) { 159 | if (verbose) { 160 | va_list valist; 161 | va_start(valist, format); 162 | __NSLogOut(format, valist); 163 | va_end(valist); 164 | } 165 | } 166 | 167 | 168 | BOOL mkdirp(NSString* path) { 169 | NSError* error = nil; 170 | BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:path 171 | withIntermediateDirectories:YES 172 | attributes:nil 173 | error:&error]; 174 | return success; 175 | } 176 | 177 | Boolean path_exists(CFTypeRef path) { 178 | if (CFGetTypeID(path) == CFStringGetTypeID()) { 179 | CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, true); 180 | Boolean result = CFURLResourceIsReachable(url, NULL); 181 | CFRelease(url); 182 | return result; 183 | } else if (CFGetTypeID(path) == CFURLGetTypeID()) { 184 | return CFURLResourceIsReachable(path, NULL); 185 | } else { 186 | return false; 187 | } 188 | } 189 | 190 | CFStringRef find_path(CFStringRef rootPath, CFStringRef namePattern) { 191 | FILE *fpipe = NULL; 192 | CFStringRef cf_command; 193 | 194 | if( !path_exists(rootPath) ) 195 | return NULL; 196 | 197 | if (CFStringFind(namePattern, CFSTR("*"), 0).location == kCFNotFound) { 198 | //No wildcards. Let's speed up the search 199 | CFStringRef path = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), rootPath, namePattern); 200 | 201 | if( path_exists(path) ) 202 | return path; 203 | 204 | CFRelease(path); 205 | return NULL; 206 | } 207 | 208 | if (CFStringFind(namePattern, CFSTR("/"), 0).location == kCFNotFound) { 209 | cf_command = CFStringCreateWithFormat(NULL, NULL, CFSTR("find '%@' -name '%@' -maxdepth 1 2>/dev/null | sort | tail -n 1"), rootPath, namePattern); 210 | } else { 211 | cf_command = CFStringCreateWithFormat(NULL, NULL, CFSTR("find '%@' -path '%@/%@' 2>/dev/null | sort | tail -n 1"), rootPath, rootPath, namePattern); 212 | } 213 | 214 | char command[1024] = { '\0' }; 215 | CFStringGetCString(cf_command, command, sizeof(command), kCFStringEncodingUTF8); 216 | CFRelease(cf_command); 217 | 218 | if (!(fpipe = (FILE *)popen(command, "r"))) 219 | on_sys_error(@"Error encountered while opening pipe"); 220 | 221 | char buffer[256] = { '\0' }; 222 | 223 | fgets(buffer, sizeof(buffer), fpipe); 224 | pclose(fpipe); 225 | 226 | strtok(buffer, "\n"); 227 | 228 | CFStringRef path = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); 229 | 230 | if( CFStringGetLength(path) > 0 && path_exists(path) ) 231 | return path; 232 | 233 | CFRelease(path); 234 | return NULL; 235 | } 236 | 237 | CFStringRef copy_xcode_dev_path() { 238 | static char xcode_dev_path[256] = { '\0' }; 239 | if (strlen(xcode_dev_path) == 0) { 240 | FILE *fpipe = NULL; 241 | char *command = "xcode-select -print-path"; 242 | 243 | if (!(fpipe = (FILE *)popen(command, "r"))) 244 | on_sys_error(@"Error encountered while opening pipe"); 245 | 246 | char buffer[256] = { '\0' }; 247 | 248 | fgets(buffer, sizeof(buffer), fpipe); 249 | pclose(fpipe); 250 | 251 | strtok(buffer, "\n"); 252 | strcpy(xcode_dev_path, buffer); 253 | } 254 | return CFStringCreateWithCString(NULL, xcode_dev_path, kCFStringEncodingUTF8); 255 | } 256 | 257 | const char *get_home() { 258 | const char* home = getenv("HOME"); 259 | if (!home) { 260 | struct passwd *pwd = getpwuid(getuid()); 261 | home = pwd->pw_dir; 262 | } 263 | return home; 264 | } 265 | 266 | CFStringRef copy_xcode_path_for_impl(CFStringRef rootPath, CFStringRef subPath, CFStringRef search) { 267 | CFStringRef searchPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), rootPath, subPath ); 268 | CFStringRef res = find_path(searchPath, search); 269 | CFRelease(searchPath); 270 | return res; 271 | } 272 | 273 | CFStringRef copy_xcode_path_for(CFStringRef subPath, CFStringRef search) { 274 | CFStringRef xcodeDevPath = copy_xcode_dev_path(); 275 | CFStringRef defaultXcodeDevPath = CFSTR("/Applications/Xcode.app/Contents/Developer"); 276 | CFStringRef path = NULL; 277 | const char* home = get_home(); 278 | 279 | // Try using xcode-select --print-path 280 | path = copy_xcode_path_for_impl(xcodeDevPath, subPath, search); 281 | 282 | // If not look in the default xcode location (xcode-select is sometimes wrong) 283 | if (path == NULL && CFStringCompare(xcodeDevPath, defaultXcodeDevPath, 0) != kCFCompareEqualTo ) 284 | path = copy_xcode_path_for_impl(defaultXcodeDevPath, subPath, search); 285 | 286 | // If not look in the users home directory, Xcode can store device support stuff there 287 | if (path == NULL) { 288 | CFRelease(xcodeDevPath); 289 | xcodeDevPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s/Library/Developer/Xcode"), home ); 290 | path = copy_xcode_path_for_impl(xcodeDevPath, subPath, search); 291 | } 292 | 293 | CFRelease(xcodeDevPath); 294 | 295 | return path; 296 | } 297 | 298 | device_desc get_device_desc(CFStringRef model) { 299 | if (model != NULL) { 300 | size_t sz = sizeof(device_db) / sizeof(device_desc); 301 | for (size_t i = 0; i < sz; i ++) { 302 | if (CFStringCompare(model, device_db[i].model, kCFCompareNonliteral | kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 303 | return device_db[i]; 304 | } 305 | } 306 | } 307 | 308 | device_desc res = device_db[UNKNOWN_DEVICE_IDX]; 309 | 310 | res.model = model; 311 | res.name = model; 312 | 313 | return res; 314 | } 315 | 316 | char * MYCFStringCopyUTF8String(CFStringRef aString) { 317 | if (aString == NULL) { 318 | return NULL; 319 | } 320 | 321 | CFIndex length = CFStringGetLength(aString); 322 | CFIndex maxSize = 323 | CFStringGetMaximumSizeForEncoding(length, 324 | kCFStringEncodingUTF8); 325 | char *buffer = (char *)malloc(maxSize); 326 | if (CFStringGetCString(aString, buffer, maxSize, 327 | kCFStringEncodingUTF8)) { 328 | return buffer; 329 | } 330 | return NULL; 331 | } 332 | 333 | CFStringRef get_device_full_name(const AMDeviceRef device) { 334 | CFStringRef full_name = NULL, 335 | device_udid = AMDeviceCopyDeviceIdentifier(device), 336 | device_name = NULL, 337 | model_name = NULL, 338 | sdk_name = NULL, 339 | arch_name = NULL; 340 | 341 | AMDeviceConnect(device); 342 | 343 | device_name = AMDeviceCopyValue(device, 0, CFSTR("DeviceName")); 344 | 345 | // Please ensure that device is connected or the name will be unknown 346 | CFStringRef model = AMDeviceCopyValue(device, 0, CFSTR("HardwareModel")); 347 | device_desc dev; 348 | if (model != NULL) { 349 | dev = get_device_desc(model); 350 | } else { 351 | dev= device_db[UNKNOWN_DEVICE_IDX]; 352 | model = dev.model; 353 | } 354 | model_name = dev.name; 355 | sdk_name = dev.sdk; 356 | arch_name = dev.arch; 357 | 358 | NSLogVerbose(@"Hardware Model: %@", model); 359 | NSLogVerbose(@"Device Name: %@", device_name); 360 | NSLogVerbose(@"Model Name: %@", model_name); 361 | NSLogVerbose(@"SDK Name: %@", sdk_name); 362 | NSLogVerbose(@"Architecture Name: %@", arch_name); 363 | 364 | if (device_name != NULL) { 365 | full_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ (%@, %@, %@, %@) a.k.a. '%@'"), device_udid, model, model_name, sdk_name, arch_name, device_name); 366 | } else { 367 | full_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ (%@, %@, %@, %@)"), device_udid, model, model_name, sdk_name, arch_name); 368 | } 369 | 370 | AMDeviceDisconnect(device); 371 | 372 | if(device_udid != NULL) 373 | CFRelease(device_udid); 374 | if(device_name != NULL) 375 | CFRelease(device_name); 376 | if(model_name != NULL) 377 | CFRelease(model_name); 378 | 379 | return full_name; 380 | } 381 | 382 | CFStringRef get_device_interface_name(const AMDeviceRef device) { 383 | // AMDeviceGetInterfaceType(device) 0=Unknown, 1 = Direct/USB, 2 = Indirect/WIFI 384 | switch(AMDeviceGetInterfaceType(device)) { 385 | case 1: 386 | return CFSTR("USB"); 387 | case 2: 388 | return CFSTR("WIFI"); 389 | default: 390 | return CFSTR("Unknown Connection"); 391 | } 392 | } 393 | 394 | CFMutableArrayRef get_device_product_version_parts(AMDeviceRef device) { 395 | CFStringRef version = AMDeviceCopyValue(device, 0, CFSTR("ProductVersion")); 396 | CFArrayRef parts = CFStringCreateArrayBySeparatingStrings(NULL, version, CFSTR(".")); 397 | CFMutableArrayRef result = CFArrayCreateMutableCopy(NULL, CFArrayGetCount(parts), parts); 398 | CFRelease(version); 399 | CFRelease(parts); 400 | return result; 401 | } 402 | 403 | CFStringRef copy_device_support_path(AMDeviceRef device, CFStringRef suffix) { 404 | time_t startTime, endTime; 405 | time( &startTime ); 406 | 407 | CFStringRef version = NULL; 408 | CFStringRef build = AMDeviceCopyValue(device, 0, CFSTR("BuildVersion")); 409 | CFStringRef deviceClass = AMDeviceCopyValue(device, 0, CFSTR("DeviceClass")); 410 | CFStringRef path = NULL; 411 | CFMutableArrayRef version_parts = get_device_product_version_parts(device); 412 | 413 | NSLogVerbose(@"Device Class: %@", deviceClass); 414 | NSLogVerbose(@"build: %@", build); 415 | 416 | CFStringRef deviceClassPath[2]; 417 | 418 | if (CFStringCompare(CFSTR("AppleTV"), deviceClass, 0) == kCFCompareEqualTo) { 419 | deviceClassPath[0] = CFSTR("Platforms/AppleTVOS.platform/DeviceSupport"); 420 | deviceClassPath[1] = CFSTR("tvOS DeviceSupport"); 421 | } else { 422 | deviceClassPath[0] = CFSTR("Platforms/iPhoneOS.platform/DeviceSupport"); 423 | deviceClassPath[1] = CFSTR("iOS DeviceSupport"); 424 | } 425 | while (CFArrayGetCount(version_parts) > 0) { 426 | version = CFStringCreateByCombiningStrings(NULL, version_parts, CFSTR(".")); 427 | NSLogVerbose(@"version: %@", version); 428 | 429 | for( int i = 0; i < 2; ++i ) { 430 | if (path == NULL) { 431 | path = copy_xcode_path_for(deviceClassPath[i], CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ (%@)/%@"), version, build, suffix)); 432 | } 433 | 434 | if (path == NULL) { 435 | path = copy_xcode_path_for(deviceClassPath[i], CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ (*)/%@"), version, suffix)); 436 | } 437 | 438 | if (path == NULL) { 439 | path = copy_xcode_path_for(deviceClassPath[i], CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), version, suffix)); 440 | } 441 | 442 | if (path == NULL) { 443 | path = copy_xcode_path_for(deviceClassPath[i], CFStringCreateWithFormat(NULL, NULL, CFSTR("%@.*/%@"), version, suffix)); 444 | } 445 | } 446 | 447 | CFRelease(version); 448 | if (path != NULL) { 449 | break; 450 | } 451 | CFArrayRemoveValueAtIndex(version_parts, CFArrayGetCount(version_parts) - 1); 452 | } 453 | 454 | for( int i = 0; i < 2; ++i ) { 455 | if (path == NULL) { 456 | path = copy_xcode_path_for(deviceClassPath[i], CFStringCreateWithFormat(NULL, NULL, CFSTR("Latest/%@"), suffix)); 457 | } 458 | } 459 | 460 | CFRelease(version_parts); 461 | CFRelease(build); 462 | CFRelease(deviceClass); 463 | if (path == NULL) 464 | on_error([NSString stringWithFormat:@"Unable to locate DeviceSupport directory with suffix '%@'. This probably means you don't have Xcode installed, you will need to launch the app manually and logging output will not be shown!", suffix]); 465 | 466 | time( &endTime ); 467 | NSLogVerbose(@"DeviceSupport directory '%@' was located. It took %.2f seconds", path, difftime(endTime,startTime)); 468 | 469 | return path; 470 | } 471 | 472 | void mount_callback(CFDictionaryRef dict, int arg) { 473 | CFStringRef status = CFDictionaryGetValue(dict, CFSTR("Status")); 474 | 475 | if (CFEqual(status, CFSTR("LookingUpImage"))) { 476 | NSLogOut(@"[ 0%%] Looking up developer disk image"); 477 | } else if (CFEqual(status, CFSTR("CopyingImage"))) { 478 | NSLogOut(@"[ 30%%] Copying DeveloperDiskImage.dmg to device"); 479 | } else if (CFEqual(status, CFSTR("MountingImage"))) { 480 | NSLogOut(@"[ 90%%] Mounting developer disk image"); 481 | } 482 | } 483 | 484 | void mount_developer_image(AMDeviceRef device) { 485 | CFStringRef image_path = copy_device_support_path(device, CFSTR("DeveloperDiskImage.dmg")); 486 | CFStringRef sig_path = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@.signature"), image_path); 487 | 488 | NSLogVerbose(@"Developer disk image: %@", image_path); 489 | 490 | FILE* sig = fopen(CFStringGetCStringPtr(sig_path, kCFStringEncodingMacRoman), "rb"); 491 | void *sig_buf = malloc(128); 492 | assert(fread(sig_buf, 1, 128, sig) == 128); 493 | fclose(sig); 494 | CFDataRef sig_data = CFDataCreateWithBytesNoCopy(NULL, sig_buf, 128, NULL); 495 | CFRelease(sig_path); 496 | 497 | CFTypeRef keys[] = { CFSTR("ImageSignature"), CFSTR("ImageType") }; 498 | CFTypeRef values[] = { sig_data, CFSTR("Developer") }; 499 | CFDictionaryRef options = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 500 | CFRelease(sig_data); 501 | 502 | int result = AMDeviceMountImage(device, image_path, options, &mount_callback, 0); 503 | if (result == 0) { 504 | NSLogOut(@"[ 95%%] Developer disk image mounted successfully"); 505 | } else if (result == 0xe8000076 /* already mounted */) { 506 | NSLogOut(@"[ 95%%] Developer disk image already mounted"); 507 | } else { 508 | on_error(@"Unable to mount developer disk image. (%x)", result); 509 | } 510 | 511 | CFRelease(image_path); 512 | CFRelease(options); 513 | } 514 | 515 | mach_error_t transfer_callback(CFDictionaryRef dict, int arg) { 516 | int percent; 517 | CFStringRef status = CFDictionaryGetValue(dict, CFSTR("Status")); 518 | CFNumberGetValue(CFDictionaryGetValue(dict, CFSTR("PercentComplete")), kCFNumberSInt32Type, &percent); 519 | 520 | if (CFEqual(status, CFSTR("CopyingFile"))) { 521 | CFStringRef path = CFDictionaryGetValue(dict, CFSTR("Path")); 522 | 523 | if ((last_path == NULL || !CFEqual(path, last_path)) && !CFStringHasSuffix(path, CFSTR(".ipa"))) { 524 | NSLogOut(@"[%3d%%] Copying %@ to device", percent / 2, path); 525 | } 526 | 527 | if (last_path != NULL) { 528 | CFRelease(last_path); 529 | } 530 | last_path = CFStringCreateCopy(NULL, path); 531 | } 532 | 533 | return 0; 534 | } 535 | 536 | mach_error_t install_callback(CFDictionaryRef dict, int arg) { 537 | int percent; 538 | CFStringRef status = CFDictionaryGetValue(dict, CFSTR("Status")); 539 | CFNumberGetValue(CFDictionaryGetValue(dict, CFSTR("PercentComplete")), kCFNumberSInt32Type, &percent); 540 | 541 | NSLogOut(@"[%3d%%] %@", (percent / 2) + 50, status); 542 | return 0; 543 | } 544 | 545 | CFURLRef copy_device_app_url(AMDeviceRef device, CFStringRef identifier) { 546 | CFDictionaryRef result = nil; 547 | 548 | NSArray *a = [NSArray arrayWithObjects: 549 | @"CFBundleIdentifier", // absolute must 550 | @"ApplicationDSID", 551 | @"ApplicationType", 552 | @"CFBundleExecutable", 553 | @"CFBundleDisplayName", 554 | @"CFBundleIconFile", 555 | @"CFBundleName", 556 | @"CFBundleShortVersionString", 557 | @"CFBundleSupportedPlatforms", 558 | @"CFBundleURLTypes", 559 | @"CodeInfoIdentifier", 560 | @"Container", 561 | @"Entitlements", 562 | @"HasSettingsBundle", 563 | @"IsUpgradeable", 564 | @"MinimumOSVersion", 565 | @"Path", 566 | @"SignerIdentity", 567 | @"UIDeviceFamily", 568 | @"UIFileSharingEnabled", 569 | @"UIStatusBarHidden", 570 | @"UISupportedInterfaceOrientations", 571 | nil]; 572 | 573 | NSDictionary *optionsDict = [NSDictionary dictionaryWithObject:a forKey:@"ReturnAttributes"]; 574 | CFDictionaryRef options = (CFDictionaryRef)optionsDict; 575 | 576 | check_error(AMDeviceLookupApplications(device, options, &result)); 577 | 578 | CFDictionaryRef app_dict = CFDictionaryGetValue(result, identifier); 579 | assert(app_dict != NULL); 580 | 581 | CFStringRef app_path = CFDictionaryGetValue(app_dict, CFSTR("Path")); 582 | assert(app_path != NULL); 583 | 584 | CFURLRef url = CFURLCreateWithFileSystemPath(NULL, app_path, kCFURLPOSIXPathStyle, true); 585 | CFRelease(result); 586 | return url; 587 | } 588 | 589 | CFStringRef copy_disk_app_identifier(CFURLRef disk_app_url) { 590 | CFURLRef plist_url = CFURLCreateCopyAppendingPathComponent(NULL, disk_app_url, CFSTR("Info.plist"), false); 591 | CFReadStreamRef plist_stream = CFReadStreamCreateWithFile(NULL, plist_url); 592 | if (!CFReadStreamOpen(plist_stream)) { 593 | on_error(@"Cannot read Info.plist file: %@", plist_url); 594 | } 595 | 596 | CFPropertyListRef plist = CFPropertyListCreateWithStream(NULL, plist_stream, 0, kCFPropertyListImmutable, NULL, NULL); 597 | CFStringRef bundle_identifier = CFRetain(CFDictionaryGetValue(plist, CFSTR("CFBundleIdentifier"))); 598 | CFReadStreamClose(plist_stream); 599 | 600 | CFRelease(plist_url); 601 | CFRelease(plist_stream); 602 | CFRelease(plist); 603 | 604 | return bundle_identifier; 605 | } 606 | 607 | CFStringRef copy_modules_search_paths_pairs(CFStringRef symbols_path, CFStringRef disk_container, CFStringRef device_container_private, CFStringRef device_container_noprivate ) 608 | { 609 | CFMutableStringRef res = CFStringCreateMutable(kCFAllocatorDefault, 0); 610 | CFStringAppendFormat(res, NULL, CFSTR("/usr \"%@/usr\""), symbols_path); 611 | CFStringAppendFormat(res, NULL, CFSTR(" /System \"%@/System\""), symbols_path); 612 | CFStringAppendFormat(res, NULL, CFSTR(" \"%@\" \"%@\""), device_container_private, disk_container); 613 | CFStringAppendFormat(res, NULL, CFSTR(" \"%@\" \"%@\""), device_container_noprivate, disk_container); 614 | CFStringAppendFormat(res, NULL, CFSTR(" /Developer \"%@/Developer\""), symbols_path); 615 | 616 | return res; 617 | } 618 | 619 | void write_lldb_prep_cmds(AMDeviceRef device, CFURLRef disk_app_url) { 620 | CFStringRef symbols_path = copy_device_support_path(device, CFSTR("Symbols")); 621 | CFMutableStringRef cmds = CFStringCreateMutableCopy(NULL, 0, LLDB_PREP_CMDS); 622 | CFRange range = { 0, CFStringGetLength(cmds) }; 623 | 624 | CFStringFindAndReplace(cmds, CFSTR("{symbols_path}"), symbols_path, range, 0); 625 | range.length = CFStringGetLength(cmds); 626 | 627 | CFMutableStringRef pmodule = CFStringCreateMutableCopy(NULL, 0, (CFStringRef)LLDB_FRUITSTRAP_MODULE); 628 | 629 | CFRange rangeLLDB = { 0, CFStringGetLength(pmodule) }; 630 | 631 | CFStringRef exitcode_app_crash_str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), exitcode_app_crash); 632 | CFStringFindAndReplace(pmodule, CFSTR("{exitcode_app_crash}"), exitcode_app_crash_str, rangeLLDB, 0); 633 | rangeLLDB.length = CFStringGetLength(pmodule); 634 | 635 | CFStringRef detect_deadlock_timeout_str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), _detectDeadlockTimeout); 636 | CFStringFindAndReplace(pmodule, CFSTR("{detect_deadlock_timeout}"), detect_deadlock_timeout_str, rangeLLDB, 0); 637 | rangeLLDB.length = CFStringGetLength(pmodule); 638 | 639 | if (args) { 640 | CFStringRef cf_args = CFStringCreateWithCString(NULL, args, kCFStringEncodingUTF8); 641 | CFStringFindAndReplace(cmds, CFSTR("{args}"), cf_args, range, 0); 642 | rangeLLDB.length = CFStringGetLength(pmodule); 643 | CFStringFindAndReplace(pmodule, CFSTR("{args}"), cf_args, rangeLLDB, 0); 644 | 645 | //printf("write_lldb_prep_cmds:args: [%s][%s]\n", CFStringGetCStringPtr (cmds,kCFStringEncodingMacRoman), 646 | // CFStringGetCStringPtr(pmodule, kCFStringEncodingMacRoman)); 647 | CFRelease(cf_args); 648 | } else { 649 | CFStringFindAndReplace(cmds, CFSTR("{args}"), CFSTR(""), range, 0); 650 | CFStringFindAndReplace(pmodule, CFSTR("{args}"), CFSTR(""), rangeLLDB, 0); 651 | //printf("write_lldb_prep_cmds: [%s][%s]\n", CFStringGetCStringPtr (cmds,kCFStringEncodingMacRoman), 652 | // CFStringGetCStringPtr(pmodule, kCFStringEncodingMacRoman)); 653 | } 654 | range.length = CFStringGetLength(cmds); 655 | 656 | CFStringRef bundle_identifier = copy_disk_app_identifier(disk_app_url); 657 | CFURLRef device_app_url = copy_device_app_url(device, bundle_identifier); 658 | CFStringRef device_app_path = CFURLCopyFileSystemPath(device_app_url, kCFURLPOSIXPathStyle); 659 | CFStringFindAndReplace(cmds, CFSTR("{device_app}"), device_app_path, range, 0); 660 | range.length = CFStringGetLength(cmds); 661 | 662 | CFStringRef disk_app_path = CFURLCopyFileSystemPath(disk_app_url, kCFURLPOSIXPathStyle); 663 | CFStringFindAndReplace(cmds, CFSTR("{disk_app}"), disk_app_path, range, 0); 664 | range.length = CFStringGetLength(cmds); 665 | 666 | CFStringRef device_port = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), port); 667 | CFStringFindAndReplace(cmds, CFSTR("{device_port}"), device_port, range, 0); 668 | range.length = CFStringGetLength(cmds); 669 | 670 | CFURLRef device_container_url = CFURLCreateCopyDeletingLastPathComponent(NULL, device_app_url); 671 | CFStringRef device_container_path = CFURLCopyFileSystemPath(device_container_url, kCFURLPOSIXPathStyle); 672 | CFMutableStringRef dcp_noprivate = CFStringCreateMutableCopy(NULL, 0, device_container_path); 673 | range.length = CFStringGetLength(dcp_noprivate); 674 | CFStringFindAndReplace(dcp_noprivate, CFSTR("/private/var/"), CFSTR("/var/"), range, 0); 675 | range.length = CFStringGetLength(cmds); 676 | CFStringFindAndReplace(cmds, CFSTR("{device_container}"), dcp_noprivate, range, 0); 677 | range.length = CFStringGetLength(cmds); 678 | 679 | CFURLRef disk_container_url = CFURLCreateCopyDeletingLastPathComponent(NULL, disk_app_url); 680 | CFStringRef disk_container_path = CFURLCopyFileSystemPath(disk_container_url, kCFURLPOSIXPathStyle); 681 | CFStringFindAndReplace(cmds, CFSTR("{disk_container}"), disk_container_path, range, 0); 682 | range.length = CFStringGetLength(cmds); 683 | 684 | CFStringRef search_paths_pairs = copy_modules_search_paths_pairs(symbols_path, disk_container_path, device_container_path, dcp_noprivate); 685 | CFStringFindAndReplace(cmds, CFSTR("{modules_search_paths_pairs}"), search_paths_pairs, range, 0); 686 | range.length = CFStringGetLength(cmds); 687 | CFRelease(search_paths_pairs); 688 | 689 | NSString* python_file_path = [NSString stringWithFormat:@"/tmp/%@/fruitstrap_", tmpUUID]; 690 | mkdirp(python_file_path); 691 | 692 | NSString* python_command = @"fruitstrap_"; 693 | if(device_id != NULL) { 694 | python_file_path = [python_file_path stringByAppendingString:[NSString stringWithUTF8String:device_id]]; 695 | python_command = [python_command stringByAppendingString:[NSString stringWithUTF8String:device_id]]; 696 | } 697 | python_file_path = [python_file_path stringByAppendingString:@".py"]; 698 | 699 | CFStringFindAndReplace(cmds, CFSTR("{python_command}"), (CFStringRef)python_command, range, 0); 700 | range.length = CFStringGetLength(cmds); 701 | CFStringFindAndReplace(cmds, CFSTR("{python_file_path}"), (CFStringRef)python_file_path, range, 0); 702 | range.length = CFStringGetLength(cmds); 703 | 704 | CFDataRef cmds_data = CFStringCreateExternalRepresentation(NULL, cmds, kCFStringEncodingUTF8, 0); 705 | NSString* prep_cmds_path = [NSString stringWithFormat:PREP_CMDS_PATH, tmpUUID]; 706 | if(device_id != NULL) { 707 | prep_cmds_path = [prep_cmds_path stringByAppendingString:[NSString stringWithUTF8String:device_id]]; 708 | } 709 | FILE *out = fopen([prep_cmds_path UTF8String], "w"); 710 | fwrite(CFDataGetBytePtr(cmds_data), CFDataGetLength(cmds_data), 1, out); 711 | // Write additional commands based on mode we're running in 712 | const char* extra_cmds; 713 | if (!interactive) 714 | { 715 | if (justlaunch) 716 | extra_cmds = lldb_prep_noninteractive_justlaunch_cmds; 717 | else 718 | extra_cmds = lldb_prep_noninteractive_cmds; 719 | } 720 | else if (nostart) 721 | extra_cmds = lldb_prep_no_cmds; 722 | else 723 | extra_cmds = lldb_prep_interactive_cmds; 724 | fwrite(extra_cmds, strlen(extra_cmds), 1, out); 725 | fclose(out); 726 | 727 | CFDataRef pmodule_data = CFStringCreateExternalRepresentation(NULL, pmodule, kCFStringEncodingUTF8, 0); 728 | 729 | out = fopen([python_file_path UTF8String], "w"); 730 | fwrite(CFDataGetBytePtr(pmodule_data), CFDataGetLength(pmodule_data), 1, out); 731 | fclose(out); 732 | 733 | CFRelease(cmds); 734 | CFRelease(symbols_path); 735 | CFRelease(bundle_identifier); 736 | CFRelease(device_app_url); 737 | CFRelease(device_app_path); 738 | CFRelease(disk_app_path); 739 | CFRelease(device_container_url); 740 | CFRelease(device_container_path); 741 | CFRelease(dcp_noprivate); 742 | CFRelease(disk_container_url); 743 | CFRelease(disk_container_path); 744 | CFRelease(cmds_data); 745 | } 746 | 747 | CFSocketRef server_socket; 748 | CFSocketRef lldb_socket; 749 | CFWriteStreamRef serverWriteStream = NULL; 750 | CFWriteStreamRef lldbWriteStream = NULL; 751 | 752 | int kill_ptree(pid_t root, int signum); 753 | void 754 | server_callback (CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) 755 | { 756 | ssize_t res; 757 | 758 | if (CFDataGetLength (data) == 0) { 759 | // close the socket on which we've got end-of-file, the server_socket. 760 | CFSocketInvalidate(s); 761 | CFRelease(s); 762 | return; 763 | } 764 | res = write (CFSocketGetNative (lldb_socket), CFDataGetBytePtr (data), CFDataGetLength (data)); 765 | } 766 | 767 | void lldb_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) 768 | { 769 | //printf ("lldb: %s\n", CFDataGetBytePtr (data)); 770 | 771 | if (CFDataGetLength (data) == 0) { 772 | // close the socket on which we've got end-of-file, the lldb_socket. 773 | CFSocketInvalidate(s); 774 | CFRelease(s); 775 | return; 776 | } 777 | write (gdbfd, CFDataGetBytePtr (data), CFDataGetLength (data)); 778 | } 779 | 780 | void fdvendor_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) { 781 | CFSocketNativeHandle socket = (CFSocketNativeHandle)(*((CFSocketNativeHandle *)data)); 782 | 783 | assert (callbackType == kCFSocketAcceptCallBack); 784 | //PRINT ("callback!\n"); 785 | 786 | lldb_socket = CFSocketCreateWithNative(NULL, socket, kCFSocketDataCallBack, &lldb_callback, NULL); 787 | int flag = 1; 788 | int res = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag)); 789 | assert(res == 0); 790 | CFRunLoopAddSource(CFRunLoopGetMain(), CFSocketCreateRunLoopSource(NULL, lldb_socket, 0), kCFRunLoopCommonModes); 791 | 792 | CFSocketInvalidate(s); 793 | CFRelease(s); 794 | } 795 | 796 | void start_remote_debug_server(AMDeviceRef device) { 797 | 798 | check_error(AMDeviceStartService(device, CFSTR("com.apple.debugserver"), &gdbfd, NULL)); 799 | assert(gdbfd > 0); 800 | 801 | /* 802 | * The debugserver connection is through a fd handle, while lldb requires a host/port to connect, so create an intermediate 803 | * socket to transfer data. 804 | */ 805 | server_socket = CFSocketCreateWithNative (NULL, gdbfd, kCFSocketDataCallBack, &server_callback, NULL); 806 | CFRunLoopAddSource(CFRunLoopGetMain(), CFSocketCreateRunLoopSource(NULL, server_socket, 0), kCFRunLoopCommonModes); 807 | 808 | struct sockaddr_in addr4; 809 | memset(&addr4, 0, sizeof(addr4)); 810 | addr4.sin_len = sizeof(addr4); 811 | addr4.sin_family = AF_INET; 812 | addr4.sin_port = htons(port); 813 | addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 814 | 815 | CFSocketRef fdvendor = CFSocketCreate(NULL, PF_INET, 0, 0, kCFSocketAcceptCallBack, &fdvendor_callback, NULL); 816 | 817 | if (port) { 818 | int yes = 1; 819 | setsockopt(CFSocketGetNative(fdvendor), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); 820 | } 821 | 822 | CFDataRef address_data = CFDataCreate(NULL, (const UInt8 *)&addr4, sizeof(addr4)); 823 | 824 | CFSocketSetAddress(fdvendor, address_data); 825 | CFRelease(address_data); 826 | socklen_t addrlen = sizeof(addr4); 827 | int res = getsockname(CFSocketGetNative(fdvendor),(struct sockaddr *)&addr4,&addrlen); 828 | assert(res == 0); 829 | port = ntohs(addr4.sin_port); 830 | 831 | CFRunLoopAddSource(CFRunLoopGetMain(), CFSocketCreateRunLoopSource(NULL, fdvendor, 0), kCFRunLoopCommonModes); 832 | } 833 | 834 | void kill_ptree_inner(pid_t root, int signum, struct kinfo_proc *kp, int kp_len) { 835 | int i; 836 | for (i = 0; i < kp_len; i++) { 837 | if (kp[i].kp_eproc.e_ppid == root) { 838 | kill_ptree_inner(kp[i].kp_proc.p_pid, signum, kp, kp_len); 839 | } 840 | } 841 | if (root != getpid()) { 842 | kill(root, signum); 843 | } 844 | } 845 | 846 | int kill_ptree(pid_t root, int signum) { 847 | int mib[3]; 848 | size_t len; 849 | mib[0] = CTL_KERN; 850 | mib[1] = KERN_PROC; 851 | mib[2] = KERN_PROC_ALL; 852 | if (sysctl(mib, 3, NULL, &len, NULL, 0) == -1) { 853 | return -1; 854 | } 855 | 856 | struct kinfo_proc *kp = calloc(1, len); 857 | if (!kp) { 858 | return -1; 859 | } 860 | 861 | if (sysctl(mib, 3, kp, &len, NULL, 0) == -1) { 862 | free(kp); 863 | return -1; 864 | } 865 | 866 | kill_ptree_inner(root, signum, kp, (int)(len / sizeof(struct kinfo_proc))); 867 | 868 | free(kp); 869 | return 0; 870 | } 871 | 872 | void killed(int signum) { 873 | // SIGKILL needed to kill lldb, probably a better way to do this. 874 | kill(0, SIGKILL); 875 | _exit(0); 876 | } 877 | 878 | void lldb_finished_handler(int signum) 879 | { 880 | int status = 0; 881 | if (waitpid(child, &status, 0) == -1) 882 | perror("waitpid failed"); 883 | _exit(WEXITSTATUS(status)); 884 | } 885 | 886 | void bring_process_to_foreground() { 887 | if (setpgid(0, 0) == -1) 888 | perror("setpgid failed"); 889 | 890 | signal(SIGTTOU, SIG_IGN); 891 | if (tcsetpgrp(STDIN_FILENO, getpid()) == -1) 892 | perror("tcsetpgrp failed"); 893 | signal(SIGTTOU, SIG_DFL); 894 | } 895 | 896 | void setup_dummy_pipe_on_stdin(int pfd[2]) { 897 | if (pipe(pfd) == -1) 898 | perror("pipe failed"); 899 | if (dup2(pfd[0], STDIN_FILENO) == -1) 900 | perror("dup2 failed"); 901 | } 902 | 903 | void setup_lldb(AMDeviceRef device, CFURLRef url) { 904 | CFStringRef device_full_name = get_device_full_name(device), 905 | device_interface_name = get_device_interface_name(device); 906 | 907 | AMDeviceConnect(device); 908 | assert(AMDeviceIsPaired(device)); 909 | check_error(AMDeviceValidatePairing(device)); 910 | check_error(AMDeviceStartSession(device)); 911 | 912 | NSLogOut(@"------ Debug phase ------"); 913 | 914 | if(AMDeviceGetInterfaceType(device) == 2) 915 | { 916 | NSLogOut(@"Cannot debug %@ over %@.", device_full_name, device_interface_name); 917 | exit(0); 918 | } 919 | 920 | NSLogOut(@"Starting debug of %@ connected through %@...", device_full_name, device_interface_name); 921 | 922 | mount_developer_image(device); // put debugserver on the device 923 | start_remote_debug_server(device); // start debugserver 924 | write_lldb_prep_cmds(device, url); // dump the necessary lldb commands into a file 925 | 926 | CFRelease(url); 927 | 928 | NSLogOut(@"[100%%] Connecting to remote debug server"); 929 | NSLogOut(@"-------------------------"); 930 | 931 | setpgid(getpid(), 0); 932 | signal(SIGHUP, killed); 933 | signal(SIGINT, killed); 934 | signal(SIGTERM, killed); 935 | // Need this before fork to avoid race conditions. For child process we remove this right after fork. 936 | signal(SIGLLDB, lldb_finished_handler); 937 | 938 | parent = getpid(); 939 | } 940 | 941 | void launch_debugger(AMDeviceRef device, CFURLRef url) { 942 | setup_lldb(device, url); 943 | int pid = fork(); 944 | if (pid == 0) { 945 | signal(SIGHUP, SIG_DFL); 946 | signal(SIGLLDB, SIG_DFL); 947 | child = getpid(); 948 | 949 | int pfd[2] = {-1, -1}; 950 | if (isatty(STDIN_FILENO)) 951 | // If we are running on a terminal, then we need to bring process to foreground for input 952 | // to work correctly on lldb's end. 953 | bring_process_to_foreground(); 954 | else 955 | // If lldb is running in a non terminal environment, then it freaks out spamming "^D" and 956 | // "quit". It seems this is caused by read() on stdin returning EOF in lldb. To hack around 957 | // this we setup a dummy pipe on stdin, so read() would block expecting "user's" input. 958 | setup_dummy_pipe_on_stdin(pfd); 959 | 960 | NSString* lldb_shell; 961 | NSString* prep_cmds = [NSString stringWithFormat:PREP_CMDS_PATH, tmpUUID]; 962 | lldb_shell = [NSString stringWithFormat:LLDB_SHELL, prep_cmds]; 963 | 964 | if(device_id != NULL) { 965 | lldb_shell = [lldb_shell stringByAppendingString: [NSString stringWithUTF8String:device_id]]; 966 | } 967 | 968 | int status = system([lldb_shell UTF8String]); // launch lldb 969 | if (status == -1) 970 | perror("failed launching lldb"); 971 | 972 | close(pfd[0]); 973 | close(pfd[1]); 974 | 975 | // Notify parent we're exiting 976 | kill(parent, SIGLLDB); 977 | // Pass lldb exit code 978 | _exit(WEXITSTATUS(status)); 979 | } else if (pid > 0) { 980 | child = pid; 981 | } else { 982 | on_sys_error(@"Fork failed"); 983 | } 984 | } 985 | 986 | void launch_debugger_and_exit(AMDeviceRef device, CFURLRef url) { 987 | setup_lldb(device,url); 988 | int pfd[2] = {-1, -1}; 989 | if (pipe(pfd) == -1) 990 | perror("Pipe failed"); 991 | int pid = fork(); 992 | if (pid == 0) { 993 | signal(SIGHUP, SIG_DFL); 994 | signal(SIGLLDB, SIG_DFL); 995 | child = getpid(); 996 | 997 | if (dup2(pfd[0],STDIN_FILENO) == -1) 998 | perror("dup2 failed"); 999 | 1000 | 1001 | NSString* prep_cmds = [NSString stringWithFormat:PREP_CMDS_PATH, tmpUUID]; 1002 | NSString* lldb_shell = [NSString stringWithFormat:LLDB_SHELL, prep_cmds]; 1003 | if(device_id != NULL) { 1004 | lldb_shell = [lldb_shell stringByAppendingString:[NSString stringWithUTF8String:device_id]]; 1005 | } 1006 | 1007 | int status = system([lldb_shell UTF8String]); // launch lldb 1008 | if (status == -1) 1009 | perror("failed launching lldb"); 1010 | 1011 | close(pfd[0]); 1012 | 1013 | // Notify parent we're exiting 1014 | kill(parent, SIGLLDB); 1015 | // Pass lldb exit code 1016 | _exit(WEXITSTATUS(status)); 1017 | } else if (pid > 0) { 1018 | child = pid; 1019 | NSLogVerbose(@"Waiting for child [Child: %d][Parent: %d]\n", child, parent); 1020 | } else { 1021 | on_sys_error(@"Fork failed"); 1022 | } 1023 | } 1024 | 1025 | CFStringRef get_bundle_id(CFURLRef app_url) 1026 | { 1027 | if (app_url == NULL) 1028 | return NULL; 1029 | 1030 | CFURLRef url = CFURLCreateCopyAppendingPathComponent(NULL, app_url, CFSTR("Info.plist"), false); 1031 | 1032 | if (url == NULL) 1033 | return NULL; 1034 | 1035 | CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, url); 1036 | CFRelease(url); 1037 | 1038 | if (stream == NULL) 1039 | return NULL; 1040 | 1041 | CFPropertyListRef plist = NULL; 1042 | if (CFReadStreamOpen(stream) == TRUE) { 1043 | plist = CFPropertyListCreateWithStream(NULL, stream, 0, 1044 | kCFPropertyListImmutable, NULL, NULL); 1045 | } 1046 | CFReadStreamClose(stream); 1047 | CFRelease(stream); 1048 | 1049 | if (plist == NULL) 1050 | return NULL; 1051 | 1052 | const void *value = CFDictionaryGetValue(plist, CFSTR("CFBundleIdentifier")); 1053 | CFStringRef bundle_id = NULL; 1054 | if (value != NULL) 1055 | bundle_id = CFRetain(value); 1056 | 1057 | CFRelease(plist); 1058 | return bundle_id; 1059 | } 1060 | 1061 | 1062 | void read_dir(service_conn_t afcFd, afc_connection* afc_conn_p, const char* dir, 1063 | void(*callback)(afc_connection *conn,const char *dir,int file)) 1064 | { 1065 | char *dir_ent; 1066 | 1067 | afc_connection afc_conn; 1068 | if (!afc_conn_p) { 1069 | afc_conn_p = &afc_conn; 1070 | AFCConnectionOpen(afcFd, 0, &afc_conn_p); 1071 | } 1072 | 1073 | afc_dictionary* afc_dict_p; 1074 | char *key, *val; 1075 | int not_dir = 0; 1076 | 1077 | unsigned int code = AFCFileInfoOpen(afc_conn_p, dir, &afc_dict_p); 1078 | if (code != 0) { 1079 | // there was a problem reading or opening the file to get info on it, abort 1080 | return; 1081 | } 1082 | 1083 | while((AFCKeyValueRead(afc_dict_p,&key,&val) == 0) && key && val) { 1084 | if (strcmp(key,"st_ifmt")==0) { 1085 | not_dir = strcmp(val,"S_IFDIR"); 1086 | break; 1087 | } 1088 | } 1089 | AFCKeyValueClose(afc_dict_p); 1090 | 1091 | if (not_dir) { 1092 | NSLogOut(@"%@", [NSString stringWithUTF8String:dir]); 1093 | } else { 1094 | NSLogOut(@"%@/", [NSString stringWithUTF8String:dir]); 1095 | } 1096 | 1097 | if (not_dir) { 1098 | if (callback) (*callback)(afc_conn_p, dir, not_dir); 1099 | return; 1100 | } 1101 | 1102 | afc_directory* afc_dir_p; 1103 | afc_error_t err = AFCDirectoryOpen(afc_conn_p, dir, &afc_dir_p); 1104 | 1105 | if (err != 0) { 1106 | // Couldn't open dir - was probably a file 1107 | return; 1108 | } else { 1109 | if (callback) (*callback)(afc_conn_p, dir, not_dir); 1110 | } 1111 | 1112 | while(true) { 1113 | err = AFCDirectoryRead(afc_conn_p, afc_dir_p, &dir_ent); 1114 | 1115 | if (err != 0 || !dir_ent) 1116 | break; 1117 | 1118 | if (strcmp(dir_ent, ".") == 0 || strcmp(dir_ent, "..") == 0) 1119 | continue; 1120 | 1121 | char* dir_joined = malloc(strlen(dir) + strlen(dir_ent) + 2); 1122 | strcpy(dir_joined, dir); 1123 | if (dir_joined[strlen(dir)-1] != '/') 1124 | strcat(dir_joined, "/"); 1125 | strcat(dir_joined, dir_ent); 1126 | read_dir(afcFd, afc_conn_p, dir_joined, callback); 1127 | free(dir_joined); 1128 | } 1129 | 1130 | AFCDirectoryClose(afc_conn_p, afc_dir_p); 1131 | } 1132 | 1133 | 1134 | // Used to send files to app-specific sandbox (Documents dir) 1135 | service_conn_t start_house_arrest_service(AMDeviceRef device) { 1136 | AMDeviceConnect(device); 1137 | assert(AMDeviceIsPaired(device)); 1138 | check_error(AMDeviceValidatePairing(device)); 1139 | check_error(AMDeviceStartSession(device)); 1140 | 1141 | service_conn_t houseFd; 1142 | 1143 | if (bundle_id == NULL) { 1144 | on_error(@"Bundle id is not specified"); 1145 | } 1146 | 1147 | CFStringRef cf_bundle_id = CFStringCreateWithCString(NULL, bundle_id, kCFStringEncodingUTF8); 1148 | if (AMDeviceStartHouseArrestService(device, cf_bundle_id, 0, &houseFd, 0) != 0) 1149 | { 1150 | on_error(@"Unable to find bundle with id: %@", [NSString stringWithUTF8String:bundle_id]); 1151 | } 1152 | 1153 | check_error(AMDeviceStopSession(device)); 1154 | check_error(AMDeviceDisconnect(device)); 1155 | CFRelease(cf_bundle_id); 1156 | 1157 | return houseFd; 1158 | } 1159 | 1160 | char const* get_filename_from_path(char const* path) 1161 | { 1162 | char const*ptr = path + strlen(path); 1163 | while (ptr > path) 1164 | { 1165 | if (*ptr == '/') 1166 | break; 1167 | --ptr; 1168 | } 1169 | if (ptr+1 >= path+strlen(path)) 1170 | return NULL; 1171 | if (ptr == path) 1172 | return ptr; 1173 | return ptr+1; 1174 | } 1175 | 1176 | void* read_file_to_memory(char const * path, size_t* file_size) 1177 | { 1178 | struct stat buf; 1179 | int err = stat(path, &buf); 1180 | if (err < 0) 1181 | { 1182 | return NULL; 1183 | } 1184 | 1185 | *file_size = buf.st_size; 1186 | FILE* fd = fopen(path, "r"); 1187 | char* content = malloc(*file_size); 1188 | if (*file_size != 0 && fread(content, *file_size, 1, fd) != 1) 1189 | { 1190 | fclose(fd); 1191 | return NULL; 1192 | } 1193 | fclose(fd); 1194 | return content; 1195 | } 1196 | 1197 | void list_files(AMDeviceRef device) 1198 | { 1199 | service_conn_t houseFd = start_house_arrest_service(device); 1200 | 1201 | afc_connection* afc_conn_p; 1202 | if (AFCConnectionOpen(houseFd, 0, &afc_conn_p) == 0) { 1203 | read_dir(houseFd, afc_conn_p, list_root?list_root:"/", NULL); 1204 | AFCConnectionClose(afc_conn_p); 1205 | } 1206 | } 1207 | 1208 | int app_exists(AMDeviceRef device) 1209 | { 1210 | if (bundle_id == NULL) { 1211 | NSLogOut(@"Bundle id is not specified."); 1212 | return 1; 1213 | } 1214 | AMDeviceConnect(device); 1215 | assert(AMDeviceIsPaired(device)); 1216 | check_error(AMDeviceValidatePairing(device)); 1217 | check_error(AMDeviceStartSession(device)); 1218 | 1219 | CFStringRef cf_bundle_id = CFStringCreateWithCString(NULL, bundle_id, kCFStringEncodingUTF8); 1220 | 1221 | NSArray *a = [NSArray arrayWithObjects:@"CFBundleIdentifier", nil]; 1222 | NSDictionary *optionsDict = [NSDictionary dictionaryWithObject:a forKey:@"ReturnAttributes"]; 1223 | CFDictionaryRef options = (CFDictionaryRef)optionsDict; 1224 | CFDictionaryRef result = nil; 1225 | check_error(AMDeviceLookupApplications(device, options, &result)); 1226 | 1227 | bool appExists = CFDictionaryContainsKey(result, cf_bundle_id); 1228 | NSLogOut(@"%@", appExists ? @"true" : @"false"); 1229 | CFRelease(cf_bundle_id); 1230 | 1231 | check_error(AMDeviceStopSession(device)); 1232 | check_error(AMDeviceDisconnect(device)); 1233 | if (appExists) 1234 | return 0; 1235 | return -1; 1236 | } 1237 | 1238 | void list_bundle_id(AMDeviceRef device) 1239 | { 1240 | AMDeviceConnect(device); 1241 | assert(AMDeviceIsPaired(device)); 1242 | check_error(AMDeviceValidatePairing(device)); 1243 | check_error(AMDeviceStartSession(device)); 1244 | 1245 | NSArray *a = [NSArray arrayWithObjects:@"CFBundleIdentifier", nil]; 1246 | NSDictionary *optionsDict = [NSDictionary dictionaryWithObject:a forKey:@"ReturnAttributes"]; 1247 | CFDictionaryRef options = (CFDictionaryRef)optionsDict; 1248 | CFDictionaryRef result = nil; 1249 | check_error(AMDeviceLookupApplications(device, options, &result)); 1250 | 1251 | CFIndex count; 1252 | count = CFDictionaryGetCount(result); 1253 | const void *keys[count]; 1254 | CFDictionaryGetKeysAndValues(result, keys, NULL); 1255 | for(int i = 0; i < count; ++i) { 1256 | NSLogOut(@"%@", (CFStringRef)keys[i]); 1257 | } 1258 | 1259 | check_error(AMDeviceStopSession(device)); 1260 | check_error(AMDeviceDisconnect(device)); 1261 | } 1262 | 1263 | void copy_file_callback(afc_connection* afc_conn_p, const char *name,int file) 1264 | { 1265 | const char *local_name=name; 1266 | 1267 | if (*local_name=='/') local_name++; 1268 | 1269 | if (*local_name=='\0') return; 1270 | 1271 | if (file) { 1272 | afc_file_ref fref; 1273 | int err = AFCFileRefOpen(afc_conn_p,name,1,&fref); 1274 | 1275 | if (err) { 1276 | fprintf(stderr,"AFCFileRefOpen(\"%s\") failed: %d\n",name,err); 1277 | return; 1278 | } 1279 | 1280 | FILE *fp = fopen(local_name,"w"); 1281 | 1282 | if (fp==NULL) { 1283 | fprintf(stderr,"fopen(\"%s\",\"w\") failer: %s\n",local_name,strerror(errno)); 1284 | AFCFileRefClose(afc_conn_p,fref); 1285 | return; 1286 | } 1287 | 1288 | char buf[4096]; 1289 | size_t sz=sizeof(buf); 1290 | 1291 | while (AFCFileRefRead(afc_conn_p,fref,buf,&sz)==0 && sz) { 1292 | fwrite(buf,sz,1,fp); 1293 | sz = sizeof(buf); 1294 | } 1295 | 1296 | AFCFileRefClose(afc_conn_p,fref); 1297 | fclose(fp); 1298 | } else { 1299 | if (mkdir(local_name,0777) && errno!=EEXIST) 1300 | fprintf(stderr,"mkdir(\"%s\") failed: %s\n",local_name,strerror(errno)); 1301 | } 1302 | } 1303 | 1304 | void download_tree(AMDeviceRef device) 1305 | { 1306 | service_conn_t houseFd = start_house_arrest_service(device); 1307 | afc_connection* afc_conn_p = NULL; 1308 | char *dirname = NULL; 1309 | 1310 | list_root = list_root? list_root : "/"; 1311 | target_filename = target_filename? target_filename : "."; 1312 | 1313 | NSString* targetPath = [NSString pathWithComponents:@[ @(target_filename), @(list_root)] ]; 1314 | mkdirp([targetPath stringByDeletingLastPathComponent]); 1315 | 1316 | if (AFCConnectionOpen(houseFd, 0, &afc_conn_p) == 0) do { 1317 | 1318 | if (target_filename) { 1319 | dirname = strdup(target_filename); 1320 | mkdirp(@(dirname)); 1321 | if (mkdir(dirname,0777) && errno!=EEXIST) { 1322 | fprintf(stderr,"mkdir(\"%s\") failed: %s\n",dirname,strerror(errno)); 1323 | break; 1324 | } 1325 | if (chdir(dirname)) { 1326 | fprintf(stderr,"chdir(\"%s\") failed: %s\n",dirname,strerror(errno)); 1327 | break; 1328 | } 1329 | } 1330 | 1331 | read_dir(houseFd, afc_conn_p, list_root, copy_file_callback); 1332 | 1333 | } while(0); 1334 | 1335 | if (dirname) free(dirname); 1336 | if (afc_conn_p) AFCConnectionClose(afc_conn_p); 1337 | } 1338 | 1339 | void upload_dir(AMDeviceRef device, afc_connection* afc_conn_p, NSString* source, NSString* destination); 1340 | void upload_single_file(AMDeviceRef device, afc_connection* afc_conn_p, NSString* sourcePath, NSString* destinationPath); 1341 | 1342 | void upload_file(AMDeviceRef device) 1343 | { 1344 | service_conn_t houseFd = start_house_arrest_service(device); 1345 | 1346 | afc_connection afc_conn; 1347 | afc_connection* afc_conn_p = &afc_conn; 1348 | AFCConnectionOpen(houseFd, 0, &afc_conn_p); 1349 | 1350 | // read_dir(houseFd, NULL, "/", NULL); 1351 | 1352 | if (!target_filename) 1353 | { 1354 | target_filename = get_filename_from_path(upload_pathname); 1355 | } 1356 | 1357 | NSString* sourcePath = [NSString stringWithUTF8String: upload_pathname]; 1358 | NSString* destinationPath = [NSString stringWithUTF8String: target_filename]; 1359 | 1360 | BOOL isDir; 1361 | bool exists = [[NSFileManager defaultManager] fileExistsAtPath: sourcePath isDirectory: &isDir]; 1362 | if (!exists) 1363 | { 1364 | on_error(@"Could not find file: %s", upload_pathname); 1365 | } 1366 | else if (isDir) 1367 | { 1368 | upload_dir(device, afc_conn_p, sourcePath, destinationPath); 1369 | } 1370 | else 1371 | { 1372 | upload_single_file(device, afc_conn_p, sourcePath, destinationPath); 1373 | } 1374 | assert(AFCConnectionClose(afc_conn_p) == 0); 1375 | } 1376 | 1377 | void upload_single_file(AMDeviceRef device, afc_connection* afc_conn_p, NSString* sourcePath, NSString* destinationPath) { 1378 | 1379 | afc_file_ref file_ref; 1380 | 1381 | // read_dir(houseFd, NULL, "/", NULL); 1382 | 1383 | size_t file_size; 1384 | void* file_content = read_file_to_memory([sourcePath fileSystemRepresentation], &file_size); 1385 | 1386 | if (!file_content) 1387 | { 1388 | on_error(@"Could not open file: %@", sourcePath); 1389 | } 1390 | 1391 | // Make sure the directory was created 1392 | { 1393 | NSString *dirpath = [destinationPath stringByDeletingLastPathComponent]; 1394 | check_error(AFCDirectoryCreate(afc_conn_p, [dirpath fileSystemRepresentation])); 1395 | } 1396 | 1397 | 1398 | int ret = AFCFileRefOpen(afc_conn_p, [destinationPath fileSystemRepresentation], 3, &file_ref); 1399 | if (ret == 0x000a) { 1400 | on_error(@"Cannot write to %@. Permission error.", destinationPath); 1401 | } 1402 | if (ret == 0x0009) { 1403 | on_error(@"Target %@ is a directory.", destinationPath); 1404 | } 1405 | assert(ret == 0); 1406 | assert(AFCFileRefWrite(afc_conn_p, file_ref, file_content, file_size) == 0); 1407 | assert(AFCFileRefClose(afc_conn_p, file_ref) == 0); 1408 | 1409 | free(file_content); 1410 | } 1411 | 1412 | void upload_dir(AMDeviceRef device, afc_connection* afc_conn_p, NSString* source, NSString* destination) 1413 | { 1414 | check_error(AFCDirectoryCreate(afc_conn_p, [destination fileSystemRepresentation])); 1415 | destination = [destination copy]; 1416 | for (NSString* item in [[NSFileManager defaultManager] contentsOfDirectoryAtPath: source error: nil]) 1417 | { 1418 | NSString* sourcePath = [source stringByAppendingPathComponent: item]; 1419 | NSString* destinationPath = [destination stringByAppendingPathComponent: item]; 1420 | BOOL isDir; 1421 | [[NSFileManager defaultManager] fileExistsAtPath: sourcePath isDirectory: &isDir]; 1422 | if (isDir) 1423 | { 1424 | upload_dir(device, afc_conn_p, sourcePath, destinationPath); 1425 | } 1426 | else 1427 | { 1428 | upload_single_file(device, afc_conn_p, sourcePath, destinationPath); 1429 | } 1430 | } 1431 | } 1432 | 1433 | void make_directory(AMDeviceRef device) { 1434 | service_conn_t houseFd = start_house_arrest_service(device); 1435 | 1436 | afc_connection afc_conn; 1437 | afc_connection* afc_conn_p = &afc_conn; 1438 | AFCConnectionOpen(houseFd, 0, &afc_conn_p); 1439 | 1440 | assert(AFCDirectoryCreate(afc_conn_p, target_filename) == 0); 1441 | assert(AFCConnectionClose(afc_conn_p) == 0); 1442 | } 1443 | 1444 | void remove_path(AMDeviceRef device) { 1445 | service_conn_t houseFd = start_house_arrest_service(device); 1446 | 1447 | afc_connection afc_conn; 1448 | afc_connection* afc_conn_p = &afc_conn; 1449 | AFCConnectionOpen(houseFd, 0, &afc_conn_p); 1450 | 1451 | 1452 | assert(AFCRemovePath(afc_conn_p, target_filename) == 0); 1453 | assert(AFCConnectionClose(afc_conn_p) == 0); 1454 | } 1455 | 1456 | void uninstall_app(AMDeviceRef device) { 1457 | CFRetain(device); // don't know if this is necessary? 1458 | 1459 | NSLogOut(@"------ Uninstall phase ------"); 1460 | 1461 | //Do we already have the bundle_id passed in via the command line? if so, use it. 1462 | CFStringRef cf_uninstall_bundle_id = NULL; 1463 | if (bundle_id != NULL) 1464 | { 1465 | cf_uninstall_bundle_id = CFStringCreateWithCString(NULL, bundle_id, kCFStringEncodingUTF8); 1466 | } else { 1467 | on_error(@"Error: you need to pass in the bundle id, (i.e. --bundle_id com.my.app)"); 1468 | } 1469 | 1470 | if (cf_uninstall_bundle_id == NULL) { 1471 | on_error(@"Error: Unable to get bundle id from user command or package %@.\nUninstall failed.", [NSString stringWithUTF8String:app_path]); 1472 | } else { 1473 | AMDeviceConnect(device); 1474 | assert(AMDeviceIsPaired(device)); 1475 | check_error(AMDeviceValidatePairing(device)); 1476 | check_error(AMDeviceStartSession(device)); 1477 | 1478 | int code = AMDeviceSecureUninstallApplication(0, device, cf_uninstall_bundle_id, 0, NULL, 0); 1479 | if (code == 0) { 1480 | NSLogOut(@"[ OK ] Uninstalled package with bundle id %@", cf_uninstall_bundle_id); 1481 | } else { 1482 | on_error(@"[ ERROR ] Could not uninstall package with bundle id %@", cf_uninstall_bundle_id); 1483 | } 1484 | check_error(AMDeviceStopSession(device)); 1485 | check_error(AMDeviceDisconnect(device)); 1486 | } 1487 | } 1488 | 1489 | void handle_device(AMDeviceRef device) { 1490 | NSLogVerbose(@"Already found device? %d", found_device); 1491 | 1492 | CFStringRef found_device_id = AMDeviceCopyDeviceIdentifier(device), 1493 | device_full_name = get_device_full_name(device), 1494 | device_interface_name = get_device_interface_name(device); 1495 | 1496 | if (detect_only) { 1497 | NSLogOut(@"[....] Found %@ connected through %@.", device_full_name, device_interface_name); 1498 | found_device = true; 1499 | return; 1500 | } 1501 | if (device_id != NULL) { 1502 | CFStringRef deviceCFSTR = CFStringCreateWithCString(NULL, device_id, kCFStringEncodingUTF8); 1503 | if (CFStringCompare(deviceCFSTR, found_device_id, kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 1504 | found_device = true; 1505 | CFRelease(deviceCFSTR); 1506 | } else { 1507 | NSLogOut(@"Skipping %@.", device_full_name); 1508 | return; 1509 | } 1510 | } else { 1511 | device_id = MYCFStringCopyUTF8String(found_device_id); 1512 | found_device = true; 1513 | } 1514 | 1515 | NSLogOut(@"[....] Using %@.", device_full_name); 1516 | 1517 | if (command_only) { 1518 | if (strcmp("list", command) == 0) { 1519 | list_files(device); 1520 | } else if (strcmp("upload", command) == 0) { 1521 | upload_file(device); 1522 | } else if (strcmp("download", command) == 0) { 1523 | download_tree(device); 1524 | } else if (strcmp("mkdir", command) == 0) { 1525 | make_directory(device); 1526 | } else if (strcmp("rm", command) == 0) { 1527 | remove_path(device); 1528 | } else if (strcmp("exists", command) == 0) { 1529 | exit(app_exists(device)); 1530 | } else if (strcmp("uninstall_only", command) == 0) { 1531 | uninstall_app(device); 1532 | } else if (strcmp("list_bundle_id", command) == 0) { 1533 | list_bundle_id(device); 1534 | } 1535 | exit(0); 1536 | } 1537 | 1538 | 1539 | CFRetain(device); // don't know if this is necessary? 1540 | 1541 | CFStringRef path = CFStringCreateWithCString(NULL, app_path, kCFStringEncodingUTF8); 1542 | CFURLRef relative_url = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, false); 1543 | CFURLRef url = CFURLCopyAbsoluteURL(relative_url); 1544 | 1545 | CFRelease(relative_url); 1546 | 1547 | if (uninstall) { 1548 | NSLogOut(@"------ Uninstall phase ------"); 1549 | 1550 | //Do we already have the bundle_id passed in via the command line? if so, use it. 1551 | CFStringRef cf_uninstall_bundle_id = NULL; 1552 | if (bundle_id != NULL) 1553 | { 1554 | cf_uninstall_bundle_id = CFStringCreateWithCString(NULL, bundle_id, kCFStringEncodingUTF8); 1555 | } else { 1556 | cf_uninstall_bundle_id = get_bundle_id(url); 1557 | } 1558 | 1559 | if (cf_uninstall_bundle_id == NULL) { 1560 | on_error(@"Error: Unable to get bundle id from user command or package %@.\nUninstall failed.", [NSString stringWithUTF8String:app_path]); 1561 | } else { 1562 | AMDeviceConnect(device); 1563 | assert(AMDeviceIsPaired(device)); 1564 | check_error(AMDeviceValidatePairing(device)); 1565 | check_error(AMDeviceStartSession(device)); 1566 | 1567 | int code = AMDeviceSecureUninstallApplication(0, device, cf_uninstall_bundle_id, 0, NULL, 0); 1568 | if (code == 0) { 1569 | NSLogOut(@"[ OK ] Uninstalled package with bundle id %@", cf_uninstall_bundle_id); 1570 | } else { 1571 | on_error(@"[ ERROR ] Could not uninstall package with bundle id %@", cf_uninstall_bundle_id); 1572 | } 1573 | check_error(AMDeviceStopSession(device)); 1574 | check_error(AMDeviceDisconnect(device)); 1575 | } 1576 | } 1577 | 1578 | if(install) { 1579 | NSLogOut(@"------ Install phase ------"); 1580 | NSLogOut(@"[ 0%%] Found %@ connected through %@, beginning install", device_full_name, device_interface_name); 1581 | 1582 | AMDeviceConnect(device); 1583 | assert(AMDeviceIsPaired(device)); 1584 | check_error(AMDeviceValidatePairing(device)); 1585 | check_error(AMDeviceStartSession(device)); 1586 | 1587 | 1588 | // NOTE: the secure version doesn't seem to require us to start the AFC service 1589 | service_conn_t afcFd; 1590 | check_error(AMDeviceSecureStartService(device, CFSTR("com.apple.afc"), NULL, &afcFd)); 1591 | check_error(AMDeviceStopSession(device)); 1592 | check_error(AMDeviceDisconnect(device)); 1593 | 1594 | CFStringRef keys[] = { CFSTR("PackageType") }; 1595 | CFStringRef values[] = { CFSTR("Developer") }; 1596 | CFDictionaryRef options = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1597 | 1598 | //assert(AMDeviceTransferApplication(afcFd, path, NULL, transfer_callback, NULL) == 0); 1599 | check_error(AMDeviceSecureTransferPath(0, device, url, options, transfer_callback, 0)); 1600 | 1601 | close(afcFd); 1602 | 1603 | 1604 | 1605 | AMDeviceConnect(device); 1606 | assert(AMDeviceIsPaired(device)); 1607 | check_error(AMDeviceValidatePairing(device)); 1608 | check_error(AMDeviceStartSession(device)); 1609 | 1610 | // // NOTE: the secure version doesn't seem to require us to start the installation_proxy service 1611 | // // Although I can't find it right now, I in some code that the first param of AMDeviceSecureInstallApplication was a "dontStartInstallProxy" 1612 | // // implying this is done for us by iOS already 1613 | 1614 | //service_conn_t installFd; 1615 | //assert(AMDeviceSecureStartService(device, CFSTR("com.apple.mobile.installation_proxy"), NULL, &installFd) == 0); 1616 | 1617 | //mach_error_t result = AMDeviceInstallApplication(installFd, path, options, install_callback, NULL); 1618 | check_error(AMDeviceSecureInstallApplication(0, device, url, options, install_callback, 0)); 1619 | 1620 | // close(installFd); 1621 | 1622 | check_error(AMDeviceStopSession(device)); 1623 | check_error(AMDeviceDisconnect(device)); 1624 | 1625 | CFRelease(path); 1626 | CFRelease(options); 1627 | 1628 | NSLogOut(@"[100%%] Installed package %@", [NSString stringWithUTF8String:app_path]); 1629 | } 1630 | 1631 | if (!debug) 1632 | exit(0); // no debug phase 1633 | 1634 | if (justlaunch) 1635 | launch_debugger_and_exit(device, url); 1636 | else 1637 | launch_debugger(device, url); 1638 | } 1639 | 1640 | void device_callback(struct am_device_notification_callback_info *info, void *arg) { 1641 | switch (info->msg) { 1642 | case ADNCI_MSG_CONNECTED: 1643 | if(device_id != NULL || !debug || AMDeviceGetInterfaceType(info->dev) != 2) { 1644 | if (no_wifi && AMDeviceGetInterfaceType(info->dev) == 2) 1645 | { 1646 | NSLogVerbose(@"Skipping wifi device (type: %d)", AMDeviceGetInterfaceType(info->dev)); 1647 | } 1648 | else 1649 | { 1650 | NSLogVerbose(@"Handling device type: %d", AMDeviceGetInterfaceType(info->dev)); 1651 | handle_device(info->dev); 1652 | } 1653 | } else if(best_device_match == NULL) { 1654 | NSLogVerbose(@"Best device match: %d", AMDeviceGetInterfaceType(info->dev)); 1655 | best_device_match = info->dev; 1656 | CFRetain(best_device_match); 1657 | } 1658 | default: 1659 | break; 1660 | } 1661 | } 1662 | 1663 | void timeout_callback(CFRunLoopTimerRef timer, void *info) { 1664 | if (found_device && (!detect_only)) { 1665 | // Don't need to exit in the justlaunch mode 1666 | if (justlaunch) 1667 | return; 1668 | 1669 | // App running for too long 1670 | NSLog(@"[ !! ] App is running for too long"); 1671 | exit(exitcode_timeout); 1672 | return; 1673 | } else if ((!found_device) && (!detect_only)) { 1674 | // Device not found timeout 1675 | if (best_device_match != NULL) { 1676 | NSLogVerbose(@"Handling best device match."); 1677 | handle_device(best_device_match); 1678 | 1679 | CFRelease(best_device_match); 1680 | best_device_match = NULL; 1681 | } 1682 | 1683 | if (!found_device) 1684 | on_error(@"Timed out waiting for device."); 1685 | } 1686 | else 1687 | { 1688 | // Device detection timeout 1689 | if (!debug) { 1690 | NSLogOut(@"[....] No more devices found."); 1691 | } 1692 | 1693 | if (detect_only && !found_device) { 1694 | exit(exitcode_error); 1695 | return; 1696 | } else { 1697 | int mypid = getpid(); 1698 | if ((parent != 0) && (parent == mypid) && (child != 0)) 1699 | { 1700 | NSLogVerbose(@"Timeout. Killing child (%d) tree.", child); 1701 | kill_ptree(child, SIGHUP); 1702 | } 1703 | } 1704 | exit(0); 1705 | } 1706 | } 1707 | 1708 | void usage(const char* app) { 1709 | NSLog( 1710 | @"Usage: %@ [OPTION]...\n" 1711 | @" -d, --debug launch the app in lldb after installation\n" 1712 | @" -i, --id the id of the device to connect to\n" 1713 | @" -c, --detect only detect if the device is connected\n" 1714 | @" -b, --bundle the path to the app bundle to be installed\n" 1715 | @" -a, --args command line arguments to pass to the app when launching it\n" 1716 | @" -t, --timeout number of seconds to wait for a device to be connected\n" 1717 | @" -u, --unbuffered don't buffer stdout\n" 1718 | @" -n, --nostart do not start the app when debugging\n" 1719 | @" -I, --noninteractive start in non interactive mode (quit when app crashes or exits)\n" 1720 | @" -L, --justlaunch just launch the app and exit lldb\n" 1721 | @" -v, --verbose enable verbose output\n" 1722 | @" -m, --noinstall directly start debugging without app install (-d not required)\n" 1723 | @" -p, --port port used for device, default: dynamic\n" 1724 | @" -r, --uninstall uninstall the app before install (do not use with -m; app cache and data are cleared) \n" 1725 | @" -9, --uninstall_only uninstall the app ONLY. Use only with -1 \n" 1726 | @" -1, --bundle_id specify bundle id for list and upload\n" 1727 | @" -l, --list list files\n" 1728 | @" -o, --upload upload file\n" 1729 | @" -w, --download download app tree\n" 1730 | @" -2, --to use together with up/download file/tree. specify target\n" 1731 | @" -D, --mkdir make directory on device\n" 1732 | @" -R, --rm remove file or directory on device (directories must be empty)\n" 1733 | @" -V, --version print the executable version \n" 1734 | @" -e, --exists check if the app with given bundle_id is installed or not \n" 1735 | @" -B, --list_bundle_id list bundle_id \n" 1736 | @" -W, --no-wifi ignore wifi devices\n" 1737 | @" --detect_deadlocks start printing backtraces for all threads periodically after specific amount of seconds\n", 1738 | [NSString stringWithUTF8String:app]); 1739 | } 1740 | 1741 | void show_version() { 1742 | NSLogOut(@"%@", @ 1743 | #include "version.h" 1744 | ); 1745 | } 1746 | 1747 | int main(int argc, char *argv[]) { 1748 | 1749 | // create a UUID for tmp purposes 1750 | CFUUIDRef uuid = CFUUIDCreate(NULL); 1751 | CFStringRef str = CFUUIDCreateString(NULL, uuid); 1752 | CFRelease(uuid); 1753 | tmpUUID = [(NSString*)str autorelease]; 1754 | 1755 | static struct option longopts[] = { 1756 | { "debug", no_argument, NULL, 'd' }, 1757 | { "id", required_argument, NULL, 'i' }, 1758 | { "bundle", required_argument, NULL, 'b' }, 1759 | { "args", required_argument, NULL, 'a' }, 1760 | { "verbose", no_argument, NULL, 'v' }, 1761 | { "timeout", required_argument, NULL, 't' }, 1762 | { "unbuffered", no_argument, NULL, 'u' }, 1763 | { "nostart", no_argument, NULL, 'n' }, 1764 | { "noninteractive", no_argument, NULL, 'I' }, 1765 | { "justlaunch", no_argument, NULL, 'L' }, 1766 | { "detect", no_argument, NULL, 'c' }, 1767 | { "version", no_argument, NULL, 'V' }, 1768 | { "noinstall", no_argument, NULL, 'm' }, 1769 | { "port", required_argument, NULL, 'p' }, 1770 | { "uninstall", no_argument, NULL, 'r' }, 1771 | { "uninstall_only", no_argument, NULL, '9'}, 1772 | { "list", optional_argument, NULL, 'l' }, 1773 | { "bundle_id", required_argument, NULL, '1'}, 1774 | { "upload", required_argument, NULL, 'o'}, 1775 | { "download", optional_argument, NULL, 'w'}, 1776 | { "to", required_argument, NULL, '2'}, 1777 | { "mkdir", required_argument, NULL, 'D'}, 1778 | { "rm", required_argument, NULL, 'R'}, 1779 | { "exists", no_argument, NULL, 'e'}, 1780 | { "list_bundle_id", no_argument, NULL, 'B'}, 1781 | { "no-wifi", no_argument, NULL, 'W'}, 1782 | { "detect_deadlocks", required_argument, NULL, 1000 }, 1783 | { NULL, 0, NULL, 0 }, 1784 | }; 1785 | int ch; 1786 | 1787 | while ((ch = getopt_long(argc, argv, "VmcdvunrILeD:R:i:b:a:t:g:x:p:1:2:o:l::w::9::B::W", longopts, NULL)) != -1) 1788 | { 1789 | switch (ch) { 1790 | case 'm': 1791 | install = 0; 1792 | debug = 1; 1793 | break; 1794 | case 'd': 1795 | debug = 1; 1796 | break; 1797 | case 'i': 1798 | device_id = optarg; 1799 | break; 1800 | case 'b': 1801 | app_path = optarg; 1802 | break; 1803 | case 'a': 1804 | args = optarg; 1805 | break; 1806 | case 'v': 1807 | verbose = 1; 1808 | break; 1809 | case 't': 1810 | _timeout = atoi(optarg); 1811 | break; 1812 | case 'u': 1813 | unbuffered = 1; 1814 | break; 1815 | case 'n': 1816 | nostart = 1; 1817 | break; 1818 | case 'I': 1819 | interactive = false; 1820 | debug = 1; 1821 | break; 1822 | case 'L': 1823 | interactive = false; 1824 | justlaunch = true; 1825 | debug = 1; 1826 | break; 1827 | case 'c': 1828 | detect_only = true; 1829 | debug = 1; 1830 | break; 1831 | case 'V': 1832 | show_version(); 1833 | return 0; 1834 | case 'p': 1835 | port = atoi(optarg); 1836 | break; 1837 | case 'r': 1838 | uninstall = 1; 1839 | break; 1840 | case '9': 1841 | command_only = true; 1842 | command = "uninstall_only"; 1843 | break; 1844 | case '1': 1845 | bundle_id = optarg; 1846 | break; 1847 | case '2': 1848 | target_filename = optarg; 1849 | break; 1850 | case 'o': 1851 | command_only = true; 1852 | upload_pathname = optarg; 1853 | command = "upload"; 1854 | break; 1855 | case 'l': 1856 | command_only = true; 1857 | command = "list"; 1858 | list_root = optarg; 1859 | break; 1860 | case 'w': 1861 | command_only = true; 1862 | command = "download"; 1863 | list_root = optarg; 1864 | break; 1865 | case 'D': 1866 | command_only = true; 1867 | target_filename = optarg; 1868 | command = "mkdir"; 1869 | break; 1870 | case 'R': 1871 | command_only = true; 1872 | target_filename = optarg; 1873 | command = "rm"; 1874 | break; 1875 | case 'e': 1876 | command_only = true; 1877 | command = "exists"; 1878 | break; 1879 | case 'B': 1880 | command_only = true; 1881 | command = "list_bundle_id"; 1882 | break; 1883 | case 'W': 1884 | no_wifi = true; 1885 | break; 1886 | case 1000: 1887 | _detectDeadlockTimeout = atoi(optarg); 1888 | break; 1889 | default: 1890 | usage(argv[0]); 1891 | return exitcode_error; 1892 | } 1893 | } 1894 | 1895 | if (!app_path && !detect_only && !command_only) { 1896 | usage(argv[0]); 1897 | on_error(@"One of -[b|c|o|l|w|D|R|e|9] is required to proceed!"); 1898 | } 1899 | 1900 | if (unbuffered) { 1901 | setbuf(stdout, NULL); 1902 | setbuf(stderr, NULL); 1903 | } 1904 | 1905 | if (detect_only && _timeout == 0) { 1906 | _timeout = 5; 1907 | } 1908 | 1909 | if (app_path) { 1910 | if (access(app_path, F_OK) != 0) { 1911 | on_sys_error(@"Can't access app path '%@'", [NSString stringWithUTF8String:app_path]); 1912 | } 1913 | } 1914 | 1915 | AMDSetLogLevel(5); // otherwise syslog gets flooded with crap 1916 | if (_timeout > 0) 1917 | { 1918 | CFRunLoopTimerRef timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + _timeout, 0, 0, 0, timeout_callback, NULL); 1919 | CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes); 1920 | NSLogOut(@"[....] Waiting up to %d seconds for iOS device to be connected", _timeout); 1921 | } 1922 | else 1923 | { 1924 | NSLogOut(@"[....] Waiting for iOS device to be connected"); 1925 | } 1926 | 1927 | AMDeviceNotificationSubscribe(&device_callback, 0, 0, NULL, ¬ify); 1928 | CFRunLoopRun(); 1929 | } 1930 | --------------------------------------------------------------------------------