summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/FUNDING.yml3
-rw-r--r--.github/workflows/build.yml30
-rw-r--r--3rd_party/ed25519/Makefile.am7
-rw-r--r--3rd_party/libsrp6a-sha512/Makefile.am3
-rw-r--r--3rd_party/libsrp6a-sha512/cstr.c62
-rw-r--r--3rd_party/libsrp6a-sha512/cstr.h14
-rw-r--r--3rd_party/libsrp6a-sha512/t_defines.h4
-rw-r--r--3rd_party/libsrp6a-sha512/t_misc.c17
-rw-r--r--3rd_party/libsrp6a-sha512/t_truerand.c8
-rw-r--r--Makefile.am1
-rw-r--r--NEWS31
-rw-r--r--README.md6
-rw-r--r--common/debug.c45
-rw-r--r--common/userpref.c53
-rw-r--r--common/userpref.h2
-rw-r--r--configure.ac39
-rw-r--r--cython/debugserver.pxi8
-rw-r--r--docs/Makefile.am3
-rw-r--r--docs/doxygen/custom.css3
-rw-r--r--docs/idevicecrashreport.119
-rw-r--r--docs/idevicenotificationproxy.115
-rw-r--r--docs/idevicesyslog.136
-rw-r--r--doxygen.cfg.in841
-rw-r--r--include/Makefile.am2
-rw-r--r--include/endianness.h7
-rw-r--r--include/libimobiledevice/afc.h30
-rw-r--r--include/libimobiledevice/libimobiledevice.h33
-rw-r--r--include/libimobiledevice/ostrace.h198
-rw-r--r--m4/ax_python_devel.m4361
-rw-r--r--src/Makefile.am1
-rw-r--r--src/afc.c205
-rw-r--r--src/house_arrest.c4
-rw-r--r--src/idevice.c184
-rw-r--r--src/idevice.h2
-rw-r--r--src/installation_proxy.c6
-rw-r--r--src/lockdown-cu.c18
-rw-r--r--src/lockdown.c73
-rw-r--r--src/misagent.c6
-rw-r--r--src/mobile_image_mounter.c4
-rw-r--r--src/notification_proxy.c9
-rw-r--r--src/ostrace.c436
-rw-r--r--src/ostrace.h37
-rw-r--r--src/sbservices.c4
-rw-r--r--tools/Makefile.am12
-rw-r--r--tools/afcclient.c214
-rw-r--r--tools/idevicebackup.c19
-rw-r--r--tools/idevicebackup2.c94
-rw-r--r--tools/idevicebtlogger.c4
-rw-r--r--tools/idevicecrashreport.c144
-rw-r--r--tools/idevicedate.c6
-rw-r--r--tools/idevicedebug.c4
-rw-r--r--tools/idevicedebugserverproxy.c4
-rw-r--r--tools/idevicedevmodectl.c6
-rw-r--r--tools/idevicediagnostics.c4
-rw-r--r--tools/ideviceenterrecovery.c4
-rw-r--r--tools/ideviceimagemounter.c45
-rw-r--r--tools/ideviceinfo.c4
-rw-r--r--tools/idevicename.c4
-rw-r--r--tools/idevicenotificationproxy.c26
-rw-r--r--tools/idevicepair.c6
-rw-r--r--tools/ideviceprovision.c33
-rw-r--r--tools/idevicescreenshot.c4
-rw-r--r--tools/idevicesetlocation.c30
-rw-r--r--tools/idevicesyslog.c688
64 files changed, 3130 insertions, 1095 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..e995b30
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,3 @@
1github: nikias
2patreon: nikias
3custom: ["https://www.paypal.me/NikiasBassen"]
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0298939..fbbf10a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -2,6 +2,7 @@ name: build
2 2
3on: 3on:
4 push: 4 push:
5 pull_request:
5 schedule: 6 schedule:
6 - cron: '0 0 1 * *' 7 - cron: '0 0 1 * *'
7 8
@@ -17,28 +18,28 @@ jobs:
17 run: | 18 run: |
18 echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV 19 echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV
19 - name: fetch libplist 20 - name: fetch libplist
20 uses: dawidd6/action-download-artifact@v3 21 uses: dawidd6/action-download-artifact@v6
21 with: 22 with:
22 github_token: ${{secrets.GITHUB_TOKEN}} 23 github_token: ${{secrets.GITHUB_TOKEN}}
23 workflow: build.yml 24 workflow: build.yml
24 name: libplist-latest_${{env.target_triplet}} 25 name: libplist-latest_${{env.target_triplet}}
25 repo: libimobiledevice/libplist 26 repo: libimobiledevice/libplist
26 - name: fetch libusbmuxd 27 - name: fetch libusbmuxd
27 uses: dawidd6/action-download-artifact@v3 28 uses: dawidd6/action-download-artifact@v6
28 with: 29 with:
29 github_token: ${{secrets.GITHUB_TOKEN}} 30 github_token: ${{secrets.GITHUB_TOKEN}}
30 workflow: build.yml 31 workflow: build.yml
31 name: libusbmuxd-latest_${{env.target_triplet}} 32 name: libusbmuxd-latest_${{env.target_triplet}}
32 repo: libimobiledevice/libusbmuxd 33 repo: libimobiledevice/libusbmuxd
33 - name: fetch libimobiledevice-glue 34 - name: fetch libimobiledevice-glue
34 uses: dawidd6/action-download-artifact@v3 35 uses: dawidd6/action-download-artifact@v6
35 with: 36 with:
36 github_token: ${{secrets.GITHUB_TOKEN}} 37 github_token: ${{secrets.GITHUB_TOKEN}}
37 workflow: build.yml 38 workflow: build.yml
38 name: libimobiledevice-glue-latest_${{env.target_triplet}} 39 name: libimobiledevice-glue-latest_${{env.target_triplet}}
39 repo: libimobiledevice/libimobiledevice-glue 40 repo: libimobiledevice/libimobiledevice-glue
40 - name: fetch libtatsu 41 - name: fetch libtatsu
41 uses: dawidd6/action-download-artifact@v3 42 uses: dawidd6/action-download-artifact@v6
42 with: 43 with:
43 github_token: ${{secrets.GITHUB_TOKEN}} 44 github_token: ${{secrets.GITHUB_TOKEN}}
44 workflow: build.yml 45 workflow: build.yml
@@ -84,28 +85,28 @@ jobs:
84 pip3 install --break-system-packages cython 85 pip3 install --break-system-packages cython
85 shell: bash 86 shell: bash
86 - name: fetch libplist 87 - name: fetch libplist
87 uses: dawidd6/action-download-artifact@v3 88 uses: dawidd6/action-download-artifact@v6
88 with: 89 with:
89 github_token: ${{secrets.GITHUB_TOKEN}} 90 github_token: ${{secrets.GITHUB_TOKEN}}
90 workflow: build.yml 91 workflow: build.yml
91 name: libplist-latest_macOS 92 name: libplist-latest_macOS
92 repo: libimobiledevice/libplist 93 repo: libimobiledevice/libplist
93 - name: fetch libusbmuxd 94 - name: fetch libusbmuxd
94 uses: dawidd6/action-download-artifact@v3 95 uses: dawidd6/action-download-artifact@v6
95 with: 96 with:
96 github_token: ${{secrets.GITHUB_TOKEN}} 97 github_token: ${{secrets.GITHUB_TOKEN}}
97 workflow: build.yml 98 workflow: build.yml
98 name: libusbmuxd-latest_macOS 99 name: libusbmuxd-latest_macOS
99 repo: libimobiledevice/libusbmuxd 100 repo: libimobiledevice/libusbmuxd
100 - name: fetch libimobiledevice-glue 101 - name: fetch libimobiledevice-glue
101 uses: dawidd6/action-download-artifact@v3 102 uses: dawidd6/action-download-artifact@v6
102 with: 103 with:
103 github_token: ${{secrets.GITHUB_TOKEN}} 104 github_token: ${{secrets.GITHUB_TOKEN}}
104 workflow: build.yml 105 workflow: build.yml
105 name: libimobiledevice-glue-latest_macOS 106 name: libimobiledevice-glue-latest_macOS
106 repo: libimobiledevice/libimobiledevice-glue 107 repo: libimobiledevice/libimobiledevice-glue
107 - name: fetch libtatsu 108 - name: fetch libtatsu
108 uses: dawidd6/action-download-artifact@v3 109 uses: dawidd6/action-download-artifact@v6
109 with: 110 with:
110 github_token: ${{secrets.GITHUB_TOKEN}} 111 github_token: ${{secrets.GITHUB_TOKEN}}
111 workflow: build.yml 112 workflow: build.yml
@@ -154,6 +155,7 @@ jobs:
154 PYTHON_EXEC_PREFIX=`$PYTHON3_BIN -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('exec_prefix'))"` 155 PYTHON_EXEC_PREFIX=`$PYTHON3_BIN -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('exec_prefix'))"`
155 PYTHON_LIBS_PATH=$PYTHON_EXEC_PREFIX/lib 156 PYTHON_LIBS_PATH=$PYTHON_EXEC_PREFIX/lib
156 PYTHON_FRAMEWORK_PATH=$PYTHON_EXEC_PREFIX/Python3 157 PYTHON_FRAMEWORK_PATH=$PYTHON_EXEC_PREFIX/Python3
158 export PYTHON_CPPFLAGS="-I$PYTHON_EXEC_PREFIX/Headers"
157 export PYTHON_LIBS="-L$PYTHON_LIBS_PATH -lpython$PYTHON_VER" 159 export PYTHON_LIBS="-L$PYTHON_LIBS_PATH -lpython$PYTHON_VER"
158 export PYTHON_EXTRA_LDFLAGS="-Wl,-stack_size,1000000 -framework CoreFoundation $PYTHON_FRAMEWORK_PATH" 160 export PYTHON_EXTRA_LDFLAGS="-Wl,-stack_size,1000000 -framework CoreFoundation $PYTHON_FRAMEWORK_PATH"
159 fi 161 fi
@@ -175,7 +177,7 @@ jobs:
175 name: libimobiledevice-latest_macOS 177 name: libimobiledevice-latest_macOS
176 path: libimobiledevice.tar 178 path: libimobiledevice.tar
177 build-windows: 179 build-windows:
178 runs-on: windows-2019 180 runs-on: windows-latest
179 defaults: 181 defaults:
180 run: 182 run:
181 shell: msys2 {0} 183 shell: msys2 {0}
@@ -196,6 +198,8 @@ jobs:
196 base-devel 198 base-devel
197 git 199 git
198 mingw-w64-${{ matrix.arch }}-gcc 200 mingw-w64-${{ matrix.arch }}-gcc
201 mingw-w64-${{ matrix.arch }}-pkg-config
202 mingw-w64-${{ matrix.arch }}-openssl
199 make 203 make
200 libtool 204 libtool
201 autoconf 205 autoconf
@@ -207,28 +211,28 @@ jobs:
207 echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV 211 echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV
208 git config --global core.autocrlf false 212 git config --global core.autocrlf false
209 - name: fetch libplist 213 - name: fetch libplist
210 uses: dawidd6/action-download-artifact@v3 214 uses: dawidd6/action-download-artifact@v6
211 with: 215 with:
212 github_token: ${{secrets.GITHUB_TOKEN}} 216 github_token: ${{secrets.GITHUB_TOKEN}}
213 workflow: build.yml 217 workflow: build.yml
214 name: libplist-latest_${{ matrix.arch }}-${{ env.dest }} 218 name: libplist-latest_${{ matrix.arch }}-${{ env.dest }}
215 repo: libimobiledevice/libplist 219 repo: libimobiledevice/libplist
216 - name: fetch libusbmuxd 220 - name: fetch libusbmuxd
217 uses: dawidd6/action-download-artifact@v3 221 uses: dawidd6/action-download-artifact@v6
218 with: 222 with:
219 github_token: ${{secrets.GITHUB_TOKEN}} 223 github_token: ${{secrets.GITHUB_TOKEN}}
220 workflow: build.yml 224 workflow: build.yml
221 name: libusbmuxd-latest_${{ matrix.arch }}-${{ env.dest }} 225 name: libusbmuxd-latest_${{ matrix.arch }}-${{ env.dest }}
222 repo: libimobiledevice/libusbmuxd 226 repo: libimobiledevice/libusbmuxd
223 - name: fetch libimobiledevice-glue 227 - name: fetch libimobiledevice-glue
224 uses: dawidd6/action-download-artifact@v3 228 uses: dawidd6/action-download-artifact@v6
225 with: 229 with:
226 github_token: ${{secrets.GITHUB_TOKEN}} 230 github_token: ${{secrets.GITHUB_TOKEN}}
227 workflow: build.yml 231 workflow: build.yml
228 name: libimobiledevice-glue-latest_${{ matrix.arch }}-${{ env.dest }} 232 name: libimobiledevice-glue-latest_${{ matrix.arch }}-${{ env.dest }}
229 repo: libimobiledevice/libimobiledevice-glue 233 repo: libimobiledevice/libimobiledevice-glue
230 - name: fetch libtatsu 234 - name: fetch libtatsu
231 uses: dawidd6/action-download-artifact@v3 235 uses: dawidd6/action-download-artifact@v6
232 with: 236 with:
233 github_token: ${{secrets.GITHUB_TOKEN}} 237 github_token: ${{secrets.GITHUB_TOKEN}}
234 workflow: build.yml 238 workflow: build.yml
diff --git a/3rd_party/ed25519/Makefile.am b/3rd_party/ed25519/Makefile.am
index d8e4e04..438cb53 100644
--- a/3rd_party/ed25519/Makefile.am
+++ b/3rd_party/ed25519/Makefile.am
@@ -15,12 +15,19 @@ libed25519_la_LIBADD =
15libed25519_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined 15libed25519_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined
16libed25519_la_SOURCES = \ 16libed25519_la_SOURCES = \
17 add_scalar.c \ 17 add_scalar.c \
18 ed25519.h \
18 fe.c \ 19 fe.c \
20 fe.h \
21 fixedint.h \
19 ge.c \ 22 ge.c \
23 ge.h \
20 keypair.c \ 24 keypair.c \
21 key_exchange.c \ 25 key_exchange.c \
26 precomp_data.h \
22 sc.c \ 27 sc.c \
28 sc.h \
23 seed.c \ 29 seed.c \
24 sign.c \ 30 sign.c \
25 sha512.c \ 31 sha512.c \
32 sha512.h \
26 verify.c 33 verify.c
diff --git a/3rd_party/libsrp6a-sha512/Makefile.am b/3rd_party/libsrp6a-sha512/Makefile.am
index 2acd582..bdacb5f 100644
--- a/3rd_party/libsrp6a-sha512/Makefile.am
+++ b/3rd_party/libsrp6a-sha512/Makefile.am
@@ -25,7 +25,8 @@ libsrp6a_sha512_la_SOURCES = \
25 t_truerand.c cstr.c \ 25 t_truerand.c cstr.c \
26 srp.c srp6a_sha512_client.c \ 26 srp.c srp6a_sha512_client.c \
27 srp.h srp_aux.h cstr.h \ 27 srp.h srp_aux.h cstr.h \
28 t_sha.c 28 t_defines.h t_pwd.h \
29 t_sha.c t_sha.h
29#if !HAVE_OPENSSL 30#if !HAVE_OPENSSL
30#libsrp6a_sha512_la_SOURCES += t_sha.c 31#libsrp6a_sha512_la_SOURCES += t_sha.c
31#endif 32#endif
diff --git a/3rd_party/libsrp6a-sha512/cstr.c b/3rd_party/libsrp6a-sha512/cstr.c
index 9856f46..58a5638 100644
--- a/3rd_party/libsrp6a-sha512/cstr.c
+++ b/3rd_party/libsrp6a-sha512/cstr.c
@@ -8,72 +8,31 @@
8#define MINSIZE 4 /* Absolute minimum - one word */ 8#define MINSIZE 4 /* Absolute minimum - one word */
9 9
10static char cstr_empty_string[] = { '\0' }; 10static char cstr_empty_string[] = { '\0' };
11static cstr_allocator * default_alloc = NULL;
12
13/*
14 * It is assumed, for efficiency, that it is okay to pass more arguments
15 * to a function than are called for, as long as the required arguments
16 * are in proper form. If extra arguments to malloc() and free() cause
17 * problems, define PEDANTIC_ARGS below.
18 */
19#ifdef PEDANTIC_ARGS
20static void * Cmalloc(int n, void * heap) { return malloc(n); }
21static void Cfree(void * p, void * heap) { free(p); }
22static cstr_allocator malloc_allocator = { Cmalloc, Cfree, NULL };
23#else
24static cstr_allocator malloc_allocator = { malloc, free, NULL };
25#endif
26
27_TYPE( void )
28cstr_set_allocator(cstr_allocator * alloc)
29{
30 default_alloc = alloc;
31}
32 11
33_TYPE( cstr * ) 12_TYPE( cstr * )
34cstr_new_alloc(cstr_allocator * alloc) 13cstr_new()
35{ 14{
36 cstr * str; 15 cstr * str;
37 16
38 if(alloc == NULL) { 17 str = (cstr *) malloc(sizeof(cstr));
39 if(default_alloc == NULL) {
40 default_alloc = &malloc_allocator;
41 }
42 alloc = default_alloc;
43 }
44
45 str = (cstr *) (*alloc->alloc)(sizeof(cstr), alloc->heap);
46 if(str) { 18 if(str) {
47 str->data = cstr_empty_string; 19 str->data = cstr_empty_string;
48 str->length = str->cap = 0; 20 str->length = str->cap = 0;
49 str->ref = 1; 21 str->ref = 1;
50 str->allocator = alloc;
51 } 22 }
52 return str; 23 return str;
53} 24}
54 25
55_TYPE( cstr * ) 26_TYPE( cstr * )
56cstr_new() 27cstr_dup(const cstr * str)
57{
58 return cstr_new_alloc(NULL);
59}
60
61_TYPE( cstr * )
62cstr_dup_alloc(const cstr * str, cstr_allocator * alloc)
63{ 28{
64 cstr * nstr = cstr_new_alloc(alloc); 29 cstr * nstr = cstr_new();
65 if(nstr) 30 if(nstr)
66 cstr_setn(nstr, str->data, str->length); 31 cstr_setn(nstr, str->data, str->length);
67 return nstr; 32 return nstr;
68} 33}
69 34
70_TYPE( cstr * ) 35_TYPE( cstr * )
71cstr_dup(const cstr * str)
72{
73 return cstr_dup_alloc(str, NULL);
74}
75
76_TYPE( cstr * )
77cstr_create(const char * s) 36cstr_create(const char * s)
78{ 37{
79 return cstr_createn(s, strlen(s)); 38 return cstr_createn(s, strlen(s));
@@ -101,9 +60,9 @@ cstr_clear_free(cstr * str)
101 if(--str->ref == 0) { 60 if(--str->ref == 0) {
102 if(str->cap > 0) { 61 if(str->cap > 0) {
103 memset(str->data, 0, str->cap); 62 memset(str->data, 0, str->cap);
104 (*str->allocator->free)(str->data, str->allocator->heap); 63 free(str->data);
105 } 64 }
106 (*str->allocator->free)(str, str->allocator->heap); 65 free(str);
107 } 66 }
108} 67}
109 68
@@ -112,8 +71,8 @@ cstr_free(cstr * str)
112{ 71{
113 if(--str->ref == 0) { 72 if(--str->ref == 0) {
114 if(str->cap > 0) 73 if(str->cap > 0)
115 (*str->allocator->free)(str->data, str->allocator->heap); 74 free(str->data);
116 (*str->allocator->free)(str, str->allocator->heap); 75 free(str);
117 } 76 }
118} 77}
119 78
@@ -121,7 +80,7 @@ _TYPE( void )
121cstr_empty(cstr * str) 80cstr_empty(cstr * str)
122{ 81{
123 if(str->cap > 0) 82 if(str->cap > 0)
124 (*str->allocator->free)(str->data, str->allocator->heap); 83 free(str->data);
125 str->data = cstr_empty_string; 84 str->data = cstr_empty_string;
126 str->length = str->cap = 0; 85 str->length = str->cap = 0;
127} 86}
@@ -137,8 +96,7 @@ cstr_alloc(cstr * str, int len)
137 if(len < MINSIZE) 96 if(len < MINSIZE)
138 len = MINSIZE; 97 len = MINSIZE;
139 98
140 t = (char *) (*str->allocator->alloc)(len * sizeof(char), 99 t = (char *) malloc(len * sizeof(char));
141 str->allocator->heap);
142 if(t) { 100 if(t) {
143 if(str->data) { 101 if(str->data) {
144 t[str->length] = 0; 102 t[str->length] = 0;
diff --git a/3rd_party/libsrp6a-sha512/cstr.h b/3rd_party/libsrp6a-sha512/cstr.h
index 7cc019a..29afea7 100644
--- a/3rd_party/libsrp6a-sha512/cstr.h
+++ b/3rd_party/libsrp6a-sha512/cstr.h
@@ -38,7 +38,7 @@
38#define _MSVC15DEXPORT 38#define _MSVC15DEXPORT
39#define _MSVC20EXPORT 39#define _MSVC20EXPORT
40#define _DLLAPI 40#define _DLLAPI
41#if defined(WINDOWS) || defined(WIN32) 41#if defined(WINDOWS) || defined(_WIN32)
42#define _CDECL _cdecl 42#define _CDECL _cdecl
43#else 43#else
44#define _CDECL 44#define _CDECL
@@ -51,27 +51,15 @@
51extern "C" { 51extern "C" {
52#endif /* __cplusplus */ 52#endif /* __cplusplus */
53 53
54/* Arguments to allocator methods ordered this way for compatibility */
55typedef struct cstr_alloc_st {
56 void * (_CDECL * alloc)(size_t n, void * heap);
57 void (_CDECL * free)(void * p, void * heap);
58 void * heap;
59} cstr_allocator;
60
61typedef struct cstr_st { 54typedef struct cstr_st {
62 char * data; /* Okay to access data and length fields directly */ 55 char * data; /* Okay to access data and length fields directly */
63 int length; 56 int length;
64 int cap; 57 int cap;
65 int ref; /* Simple reference counter */ 58 int ref; /* Simple reference counter */
66 cstr_allocator * allocator;
67} cstr; 59} cstr;
68 60
69_TYPE( void ) cstr_set_allocator P((cstr_allocator * alloc));
70
71_TYPE( cstr * ) cstr_new P((void)); 61_TYPE( cstr * ) cstr_new P((void));
72_TYPE( cstr * ) cstr_new_alloc P((cstr_allocator * alloc));
73_TYPE( cstr * ) cstr_dup P((const cstr * str)); 62_TYPE( cstr * ) cstr_dup P((const cstr * str));
74_TYPE( cstr * ) cstr_dup_alloc P((const cstr * str, cstr_allocator * alloc));
75_TYPE( cstr * ) cstr_create P((const char * s)); 63_TYPE( cstr * ) cstr_create P((const char * s));
76_TYPE( cstr * ) cstr_createn P((const char * s, int len)); 64_TYPE( cstr * ) cstr_createn P((const char * s, int len));
77 65
diff --git a/3rd_party/libsrp6a-sha512/t_defines.h b/3rd_party/libsrp6a-sha512/t_defines.h
index 447263f..a2a5fe5 100644
--- a/3rd_party/libsrp6a-sha512/t_defines.h
+++ b/3rd_party/libsrp6a-sha512/t_defines.h
@@ -65,7 +65,7 @@
65#define _MSVC15DEXPORT 65#define _MSVC15DEXPORT
66#define _MSVC20EXPORT 66#define _MSVC20EXPORT
67#define _DLLAPI 67#define _DLLAPI
68#if defined(WINDOWS) || defined(WIN32) 68#if defined(WINDOWS) || defined(_WIN32)
69#define _CDECL _cdecl 69#define _CDECL _cdecl
70#else 70#else
71#define _CDECL 71#define _CDECL
@@ -122,7 +122,7 @@ char *strchr(), *strrchr(), *strtok();
122#define USE_SGTTY 122#define USE_SGTTY
123#endif 123#endif
124 124
125#ifdef WIN32 125#ifdef _WIN32
126#define USE_FTIME 1 126#define USE_FTIME 1
127#define USE_RENAME 1 127#define USE_RENAME 1
128#define NO_FCHMOD 1 128#define NO_FCHMOD 1
diff --git a/3rd_party/libsrp6a-sha512/t_misc.c b/3rd_party/libsrp6a-sha512/t_misc.c
index 3a2cda1..34b9509 100644
--- a/3rd_party/libsrp6a-sha512/t_misc.c
+++ b/3rd_party/libsrp6a-sha512/t_misc.c
@@ -38,7 +38,7 @@
38#include <sys/stat.h> 38#include <sys/stat.h>
39#include <fcntl.h> 39#include <fcntl.h>
40 40
41#ifdef WIN32 41#ifdef _WIN32
42#include <process.h> 42#include <process.h>
43#include <io.h> 43#include <io.h>
44#endif 44#endif
@@ -77,7 +77,12 @@ SHA1_CTX randctxt;
77 * tricks with variable ordering and sometimes define quirky 77 * tricks with variable ordering and sometimes define quirky
78 * environment variables like $WINDOWID or $_. 78 * environment variables like $WINDOWID or $_.
79 */ 79 */
80#ifdef __APPLE__
81#include <crt_externs.h>
82#define environ (*_NSGetEnviron())
83#else
80extern char ** environ; 84extern char ** environ;
85#endif
81 86
82static void 87static void
83t_envhash(unsigned char * out) 88t_envhash(unsigned char * out)
@@ -207,7 +212,7 @@ t_initrand()
207#if defined(OPENSSL) /* OpenSSL has nifty win32 entropy-gathering code */ 212#if defined(OPENSSL) /* OpenSSL has nifty win32 entropy-gathering code */
208#if OPENSSL_VERSION_NUMBER >= 0x00905100 213#if OPENSSL_VERSION_NUMBER >= 0x00905100
209 r = RAND_status(); 214 r = RAND_status();
210#if defined(WINDOWS) || defined(WIN32) 215#if defined(WINDOWS) || defined(_WIN32)
211 if(r) /* Don't do the Unix-y stuff on Windows if possible */ 216 if(r) /* Don't do the Unix-y stuff on Windows if possible */
212 return; 217 return;
213#else 218#else
@@ -220,7 +225,7 @@ t_initrand()
220 if(r > 0) { 225 if(r > 0) {
221 yarrow_add_entropy(entropy, r, &g_rng); 226 yarrow_add_entropy(entropy, r, &g_rng);
222 memset(entropy, 0, sizeof(entropy)); 227 memset(entropy, 0, sizeof(entropy));
223# if defined(WINDOWS) || defined(WIN32) 228# if defined(WINDOWS) || defined(_WIN32)
224 /* Don't do the Unix-y stuff on Windows if possible */ 229 /* Don't do the Unix-y stuff on Windows if possible */
225 yarrow_ready(&g_rng); 230 yarrow_ready(&g_rng);
226 return; 231 return;
@@ -228,13 +233,13 @@ t_initrand()
228 } 233 }
229#endif 234#endif
230 235
231#if !defined(WINDOWS) && !defined(WIN32) 236#if !defined(WINDOWS) && !defined(_WIN32)
232 i = open("/dev/urandom", O_RDONLY); 237 i = open("/dev/urandom", O_RDONLY);
233 if(i > 0) { 238 if(i > 0) {
234 r += read(i, preseed.devrand, sizeof(preseed.devrand)); 239 r += read(i, preseed.devrand, sizeof(preseed.devrand));
235 close(i); 240 close(i);
236 } 241 }
237#endif /* !WINDOWS && !WIN32 */ 242#endif /* !WINDOWS && !_WIN32 */
238 243
239 /* Resort to truerand only if desperate for some Real entropy */ 244 /* Resort to truerand only if desperate for some Real entropy */
240 if(r == 0) 245 if(r == 0)
@@ -250,7 +255,7 @@ t_initrand()
250 preseed.subsec = t.tv_usec; 255 preseed.subsec = t.tv_usec;
251#endif 256#endif
252 preseed.pid = getpid(); 257 preseed.pid = getpid();
253#ifndef WIN32 258#ifndef _WIN32
254 preseed.ppid = getppid(); 259 preseed.ppid = getppid();
255#endif 260#endif
256 t_envhash(preseed.envh); 261 t_envhash(preseed.envh);
diff --git a/3rd_party/libsrp6a-sha512/t_truerand.c b/3rd_party/libsrp6a-sha512/t_truerand.c
index f995ed7..cd27d0d 100644
--- a/3rd_party/libsrp6a-sha512/t_truerand.c
+++ b/3rd_party/libsrp6a-sha512/t_truerand.c
@@ -54,7 +54,7 @@
54 54
55#include "t_defines.h" 55#include "t_defines.h"
56 56
57#ifdef WIN32 57#ifdef _WIN32
58 58
59# ifdef CRYPTOLIB 59# ifdef CRYPTOLIB
60 60
@@ -69,7 +69,7 @@ raw_truerand()
69 return truerand(); 69 return truerand();
70} 70}
71 71
72# else /* !CRYPTOLIB && WIN32 */ 72# else /* !CRYPTOLIB && _WIN32 */
73 73
74#include <windows.h> 74#include <windows.h>
75#include <wtypes.h> 75#include <wtypes.h>
@@ -128,7 +128,7 @@ raw_truerand() {
128 128
129# endif /* CRYPTOLIB */ 129# endif /* CRYPTOLIB */
130 130
131#else /* !WIN32 */ 131#else /* !_WIN32 */
132 132
133#include <signal.h> 133#include <signal.h>
134#include <setjmp.h> 134#include <setjmp.h>
@@ -238,4 +238,4 @@ raw_n_truerand(int n)
238 return v % n; 238 return v % n;
239} 239}
240 240
241#endif /* !CRYPTOLIB || !WIN32 */ 241#endif /* !CRYPTOLIB || !_WIN32 */
diff --git a/Makefile.am b/Makefile.am
index 352b28f..f429f2f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,6 @@ ACLOCAL_AMFLAGS = -I m4
3SUBDIRS = 3rd_party common src include $(CYTHON_SUB) tools docs 3SUBDIRS = 3rd_party common src include $(CYTHON_SUB) tools docs
4 4
5EXTRA_DIST = \ 5EXTRA_DIST = \
6 docs \
7 README.md \ 6 README.md \
8 git-version-gen 7 git-version-gen
9 8
diff --git a/NEWS b/NEWS
index 72823dc..4e075ce 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,34 @@
1Version 1.4.0
2~~~~~~~~~~~~~
3
4* Development release
5 - From now on, releases will be made more frequently
6* Changes:
7 - Add support for MbedTLS
8 - Add Reverse Proxy implementation
9 - Add support for wireless pairing (AppleTV)
10 - Embed 3rd party libraries for ed25519 and SRP6a
11 - Fixes in idevicedebug
12 - idevicecrashreport: Allow filtering crash reports by filename
13 - Add idevicedevmodectl tool
14 - Fixes for idevicebackup2
15 - Add property_list_client_get_service_client() and service_get_connection() functions
16 - Add idevicebtlogger
17 - Add new idevice_events_subscribe/unsubscribe API
18 - Move LIBIMOBILEDEVICE_API to public headers
19 - Add afc_strerror function
20 - Add libimobiledevice_version() function
21 - Use libimobiledevice-glue's SHA1 implementation
22 - Add support for iOS 17+ Personalized Developer Disk image mounting
23 - Fix compilation on MSVC
24 - Add idevice_strerror() to interface
25 - Add new idevice_get_device_version() to interface
26 - Add os_trace_relay service implementation
27 - Fixes for idevicesyslog
28 - afc: Add afc_get_file_info_plist and afc_get_device_info_plist functions
29 ... and several other internal changes
30
31
1Version 1.3.0 32Version 1.3.0
2~~~~~~~~~~~~~ 33~~~~~~~~~~~~~
3 34
diff --git a/README.md b/README.md
index ec057a6..32e1570 100644
--- a/README.md
+++ b/README.md
@@ -179,8 +179,8 @@ We are still working on the guidelines so bear with us!
179## Links 179## Links
180 180
181* Homepage: https://libimobiledevice.org/ 181* Homepage: https://libimobiledevice.org/
182* Repository: https://git.libimobiledevice.org/libimobiledevice.git 182* Repository: https://github.com/libimobiledevice/libimobiledevice.git
183* Repository (Mirror): https://github.com/libimobiledevice/libimobiledevice.git 183* Repository (Mirror): https://git.libimobiledevice.org/libimobiledevice.git
184* Issue Tracker: https://github.com/libimobiledevice/libimobiledevice/issues 184* Issue Tracker: https://github.com/libimobiledevice/libimobiledevice/issues
185* Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel 185* Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel
186* Twitter: https://twitter.com/libimobiledev 186* Twitter: https://twitter.com/libimobiledev
@@ -198,4 +198,4 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc.
198This project is an independent software and has not been authorized, sponsored, 198This project is an independent software and has not been authorized, sponsored,
199or otherwise approved by Apple Inc. 199or otherwise approved by Apple Inc.
200 200
201README Updated on: 2024-06-27 201README Updated on: 2024-10-22
diff --git a/common/debug.c b/common/debug.c
index cf1bc2f..7a593fc 100644
--- a/common/debug.c
+++ b/common/debug.c
@@ -30,6 +30,9 @@
30#include <stdint.h> 30#include <stdint.h>
31#include <stdlib.h> 31#include <stdlib.h>
32#include <time.h> 32#include <time.h>
33#ifndef _WIN32
34#include <sys/time.h>
35#endif
33 36
34#include "src/idevice.h" 37#include "src/idevice.h"
35#include "debug.h" 38#include "debug.h"
@@ -51,27 +54,31 @@ void internal_set_debug_level(int level)
51#ifndef STRIP_DEBUG_CODE 54#ifndef STRIP_DEBUG_CODE
52static void debug_print_line(const char *func, const char *file, int line, const char *buffer) 55static void debug_print_line(const char *func, const char *file, int line, const char *buffer)
53{ 56{
54 char *str_time = NULL; 57 char str_time[24];
55 char *header = NULL; 58#ifdef _WIN32
59 SYSTEMTIME lt;
60 GetLocalTime(&lt);
61 snprintf(str_time, 24, "%02d:%02d:%02d.%03d", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds);
62#else
63#ifdef HAVE_GETTIMEOFDAY
64 struct timeval tv;
65 struct tm *tp;
66 gettimeofday(&tv, NULL);
67#ifdef HAVE_LOCALTIME_R
68 struct tm tp_;
69 tp = localtime_r(&tv.tv_sec, &tp_);
70#else
71 tp = localtime(&tv.tv_sec);
72#endif
73 strftime(str_time, 9, "%H:%M:%S", tp);
74 snprintf(str_time+8, 10, ".%03d", (int)tv.tv_usec/1000);
75#else
56 time_t the_time; 76 time_t the_time;
57
58 time(&the_time); 77 time(&the_time);
59 str_time = (char*)malloc(255); 78 strftime(str_time, 15, "%H:%M:%S", localtime (&the_time));
60 strftime(str_time, 254, "%H:%M:%S", localtime (&the_time)); 79#endif
61 80#endif
62 /* generate header text */ 81 fprintf(stderr, "%s %s:%d %s(): %s\n", str_time, file, line, func, buffer);
63 if(asprintf(&header, "%s %s:%d %s()", str_time, file, line, func)<0){}
64 free (str_time);
65
66 /* trim ending newlines */
67
68 /* print header */
69 fprintf(stderr, "%s: ", header);
70
71 /* print actual debug content */
72 fprintf(stderr, "%s\n", buffer);
73
74 free (header);
75} 82}
76#endif 83#endif
77 84
diff --git a/common/userpref.c b/common/userpref.c
index 48bcfcb..76945e1 100644
--- a/common/userpref.c
+++ b/common/userpref.c
@@ -29,13 +29,18 @@
29#include <stdint.h> 29#include <stdint.h>
30#include <stdlib.h> 30#include <stdlib.h>
31#include <string.h> 31#include <string.h>
32#include <errno.h>
33
32#ifdef HAVE_SYS_TYPES_H 34#ifdef HAVE_SYS_TYPES_H
33#include <sys/types.h> 35#include <sys/types.h>
34#endif 36#endif
35#ifndef WIN32 37#include <dirent.h>
38#ifndef _WIN32
36#include <pwd.h> 39#include <pwd.h>
37#endif
38#include <unistd.h> 40#include <unistd.h>
41#include <libgen.h>
42#include <sys/stat.h>
43#endif
39#include <usbmuxd.h> 44#include <usbmuxd.h>
40#if defined(HAVE_OPENSSL) 45#if defined(HAVE_OPENSSL)
41#include <openssl/bn.h> 46#include <openssl/bn.h>
@@ -64,12 +69,7 @@
64#error No supported TLS/SSL library enabled 69#error No supported TLS/SSL library enabled
65#endif 70#endif
66 71
67#include <dirent.h> 72#ifdef _WIN32
68#include <libgen.h>
69#include <sys/stat.h>
70#include <errno.h>
71
72#ifdef WIN32
73#include <shlobj.h> 73#include <shlobj.h>
74#endif 74#endif
75 75
@@ -77,6 +77,7 @@
77#define ETIMEDOUT 138 77#define ETIMEDOUT 138
78#endif 78#endif
79 79
80#include <libimobiledevice/libimobiledevice.h>
80#include <libimobiledevice-glue/utils.h> 81#include <libimobiledevice-glue/utils.h>
81 82
82#include "userpref.h" 83#include "userpref.h"
@@ -93,7 +94,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
93}; 94};
94#endif 95#endif
95 96
96#ifdef WIN32 97#ifdef _WIN32
97#define DIR_SEP '\\' 98#define DIR_SEP '\\'
98#define DIR_SEP_S "\\" 99#define DIR_SEP_S "\\"
99#else 100#else
@@ -103,7 +104,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
103 104
104#define USERPREF_CONFIG_EXTENSION ".plist" 105#define USERPREF_CONFIG_EXTENSION ".plist"
105 106
106#ifdef WIN32 107#ifdef _WIN32
107#define USERPREF_CONFIG_DIR "Apple"DIR_SEP_S"Lockdown" 108#define USERPREF_CONFIG_DIR "Apple"DIR_SEP_S"Lockdown"
108#else 109#else
109#define USERPREF_CONFIG_DIR "lockdown" 110#define USERPREF_CONFIG_DIR "lockdown"
@@ -113,7 +114,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
113 114
114static char *__config_dir = NULL; 115static char *__config_dir = NULL;
115 116
116#ifdef WIN32 117#ifdef _WIN32
117static char *userpref_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, long *items_written) 118static char *userpref_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, long *items_written)
118{ 119{
119 if (!unistr || (len <= 0)) return NULL; 120 if (!unistr || (len <= 0)) return NULL;
@@ -155,7 +156,7 @@ const char *userpref_get_config_dir()
155 if (__config_dir) 156 if (__config_dir)
156 return __config_dir; 157 return __config_dir;
157 158
158#ifdef WIN32 159#ifdef _WIN32
159 wchar_t path[MAX_PATH+1]; 160 wchar_t path[MAX_PATH+1];
160 HRESULT hr; 161 HRESULT hr;
161 LPITEMIDLIST pidl = NULL; 162 LPITEMIDLIST pidl = NULL;
@@ -419,7 +420,7 @@ static int _mbedtls_x509write_crt_set_basic_constraints_critical(mbedtls_x509wri
419 * 420 *
420 * @return 1 if keys were successfully generated, 0 otherwise 421 * @return 1 if keys were successfully generated, 0 otherwise
421 */ 422 */
422userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key) 423userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key, unsigned int device_version)
423{ 424{
424 userpref_error_t ret = USERPREF_E_SSL_ERROR; 425 userpref_error_t ret = USERPREF_E_SSL_ERROR;
425 426
@@ -484,7 +485,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
484 X509_set_pubkey(root_cert, root_pkey); 485 X509_set_pubkey(root_cert, root_pkey);
485 486
486 /* sign root cert with root private key */ 487 /* sign root cert with root private key */
487 X509_sign(root_cert, root_pkey, EVP_sha1()); 488 X509_sign(root_cert, root_pkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? EVP_sha1() : EVP_sha256());
488 } 489 }
489 490
490 /* create host certificate */ 491 /* create host certificate */
@@ -517,7 +518,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
517 X509_set_pubkey(host_cert, host_pkey); 518 X509_set_pubkey(host_cert, host_pkey);
518 519
519 /* sign host cert with root private key */ 520 /* sign host cert with root private key */
520 X509_sign(host_cert, root_pkey, EVP_sha1()); 521 X509_sign(host_cert, root_pkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? EVP_sha1() : EVP_sha256());
521 } 522 }
522 523
523 if (root_cert && root_pkey && host_cert && host_pkey) { 524 if (root_cert && root_pkey && host_cert && host_pkey) {
@@ -609,7 +610,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
609 X509_add_ext_helper(dev_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment"); 610 X509_add_ext_helper(dev_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment");
610 611
611 /* sign device certificate with root private key */ 612 /* sign device certificate with root private key */
612 if (X509_sign(dev_cert, root_pkey, EVP_sha1())) { 613 if (X509_sign(dev_cert, root_pkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? EVP_sha1() : EVP_sha256())) {
613 /* if signing succeeded, export in PEM format */ 614 /* if signing succeeded, export in PEM format */
614 BIO* membp = BIO_new(BIO_s_mem()); 615 BIO* membp = BIO_new(BIO_s_mem());
615 if (PEM_write_bio_X509(membp, dev_cert) > 0) { 616 if (PEM_write_bio_X509(membp, dev_cert) > 0) {
@@ -661,7 +662,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
661 gnutls_x509_crt_set_ca_status(root_cert, 1); 662 gnutls_x509_crt_set_ca_status(root_cert, 1);
662 gnutls_x509_crt_set_activation_time(root_cert, time(NULL)); 663 gnutls_x509_crt_set_activation_time(root_cert, time(NULL));
663 gnutls_x509_crt_set_expiration_time(root_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); 664 gnutls_x509_crt_set_expiration_time(root_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
664 gnutls_x509_crt_sign2(root_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0); 665 gnutls_x509_crt_sign2(root_cert, root_cert, root_privkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0);
665 666
666 gnutls_x509_crt_set_key(host_cert, host_privkey); 667 gnutls_x509_crt_set_key(host_cert, host_privkey);
667 gnutls_x509_crt_set_serial(host_cert, "\x01", 1); 668 gnutls_x509_crt_set_serial(host_cert, "\x01", 1);
@@ -670,7 +671,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
670 gnutls_x509_crt_set_key_usage(host_cert, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE); 671 gnutls_x509_crt_set_key_usage(host_cert, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE);
671 gnutls_x509_crt_set_activation_time(host_cert, time(NULL)); 672 gnutls_x509_crt_set_activation_time(host_cert, time(NULL));
672 gnutls_x509_crt_set_expiration_time(host_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); 673 gnutls_x509_crt_set_expiration_time(host_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
673 gnutls_x509_crt_sign2(host_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0); 674 gnutls_x509_crt_sign2(host_cert, root_cert, root_privkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0);
674 675
675 /* export to PEM format */ 676 /* export to PEM format */
676 size_t root_key_export_size = 0; 677 size_t root_key_export_size = 0;
@@ -768,17 +769,17 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
768 gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); 769 gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
769 770
770 /* use custom hash generation for compatibility with the "Apple ecosystem" */ 771 /* use custom hash generation for compatibility with the "Apple ecosystem" */
771 const gnutls_digest_algorithm_t dig_sha1 = GNUTLS_DIG_SHA1; 772 const gnutls_digest_algorithm_t dig_sha = (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256;
772 size_t hash_size = gnutls_hash_get_len(dig_sha1); 773 size_t hash_size = gnutls_hash_get_len(dig_sha);
773 unsigned char hash[hash_size]; 774 unsigned char hash[hash_size];
774 if (gnutls_hash_fast(dig_sha1, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) { 775 if (gnutls_hash_fast(dig_sha, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) {
775 debug_info("ERROR: Failed to generate SHA1 for public key"); 776 debug_info("ERROR: Failed to generate SHA for public key");
776 } else { 777 } else {
777 gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size); 778 gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size);
778 } 779 }
779 780
780 gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT); 781 gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT);
781 gnutls_error = gnutls_x509_crt_sign2(dev_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0); 782 gnutls_error = gnutls_x509_crt_sign2(dev_cert, root_cert, root_privkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0);
782 if (GNUTLS_E_SUCCESS == gnutls_error) { 783 if (GNUTLS_E_SUCCESS == gnutls_error) {
783 /* if everything went well, export in PEM format */ 784 /* if everything went well, export in PEM format */
784 size_t export_size = 0; 785 size_t export_size = 0;
@@ -872,7 +873,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
872 873
873 /* sign root cert with root private key */ 874 /* sign root cert with root private key */
874 mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); 875 mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey);
875 mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1); 876 mbedtls_x509write_crt_set_md_alg(&cert, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256);
876 877
877 unsigned char outbuf[16384]; 878 unsigned char outbuf[16384];
878 879
@@ -931,7 +932,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
931 932
932 /* sign host cert with root private key */ 933 /* sign host cert with root private key */
933 mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); 934 mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey);
934 mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1); 935 mbedtls_x509write_crt_set_md_alg(&cert, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256);
935 936
936 /* write host private key */ 937 /* write host private key */
937 mbedtls_pk_write_key_pem(&host_pkey, outbuf, sizeof(outbuf)); 938 mbedtls_pk_write_key_pem(&host_pkey, outbuf, sizeof(outbuf));
@@ -991,7 +992,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
991 992
992 /* sign device certificate with root private key */ 993 /* sign device certificate with root private key */
993 mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); 994 mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey);
994 mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1); 995 mbedtls_x509write_crt_set_md_alg(&cert, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256);
995 996
996 /* write device certificate */ 997 /* write device certificate */
997 mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg); 998 mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg);
diff --git a/common/userpref.h b/common/userpref.h
index 75bb8b7..9a1832c 100644
--- a/common/userpref.h
+++ b/common/userpref.h
@@ -68,7 +68,7 @@ userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_recor
68userpref_error_t userpref_save_pair_record(const char *udid, uint32_t device_id, plist_t pair_record); 68userpref_error_t userpref_save_pair_record(const char *udid, uint32_t device_id, plist_t pair_record);
69userpref_error_t userpref_delete_pair_record(const char *udid); 69userpref_error_t userpref_delete_pair_record(const char *udid);
70 70
71userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key); 71userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key, unsigned int device_version);
72#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) 72#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)
73userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key); 73userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key);
74userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert); 74userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert);
diff --git a/configure.ac b/configure.ac
index c67e896..055fe04 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,7 +15,7 @@ dnl libtool versioning
15# changes to the signature and the semantic) 15# changes to the signature and the semantic)
16# ? :+1 : ? == just internal changes 16# ? :+1 : ? == just internal changes
17# CURRENT : REVISION : AGE 17# CURRENT : REVISION : AGE
18LIBIMOBILEDEVICE_SO_VERSION=6:0:0 18LIBIMOBILEDEVICE_SO_VERSION=7:0:1
19 19
20AC_SUBST(LIBIMOBILEDEVICE_SO_VERSION) 20AC_SUBST(LIBIMOBILEDEVICE_SO_VERSION)
21 21
@@ -70,7 +70,7 @@ AC_TYPE_UINT32_T
70AC_TYPE_UINT8_T 70AC_TYPE_UINT8_T
71 71
72# Checks for library functions. 72# Checks for library functions.
73AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf getifaddrs]) 73AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf getifaddrs gettimeofday localtime_r])
74 74
75AC_CHECK_HEADER(endian.h, [ac_cv_have_endian_h="yes"], [ac_cv_have_endian_h="no"]) 75AC_CHECK_HEADER(endian.h, [ac_cv_have_endian_h="yes"], [ac_cv_have_endian_h="no"])
76if test "x$ac_cv_have_endian_h" = "xno"; then 76if test "x$ac_cv_have_endian_h" = "xno"; then
@@ -84,8 +84,24 @@ if test "x$ac_cv_have_endian_h" = "xno"; then
84 fi 84 fi
85fi 85fi
86 86
87CACHED_CFLAGS="$CFLAGS"
88CFLAGS+=" $libplist_CFLAGS -Werror"
89
87AC_CHECK_DECL([plist_from_json], [AC_DEFINE([HAVE_PLIST_JSON], [1], [Define if libplist has JSON support])], [], [[#include <plist/plist.h>]]) 90AC_CHECK_DECL([plist_from_json], [AC_DEFINE([HAVE_PLIST_JSON], [1], [Define if libplist has JSON support])], [], [[#include <plist/plist.h>]])
88 91
92# check if libplist has plist_new_unix_date()
93AC_CACHE_CHECK(for plist_new_unix_date, ac_cv_plist_unix_date,
94 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
95 #include <plist/plist.h>
96 ]], [[
97 return plist_new_unix_date(0) ? 0 : 1
98 ]])],[ac_cv_plist_unix_date=yes],[ac_cv_plist_unix_date=no]))
99if test "$ac_cv_plist_unix_date" = "yes"; then
100 AC_DEFINE(HAVE_PLIST_UNIX_DATE, 1, [Define if libplist has new unix date API (>= 2.7.0)])
101fi
102
103CFLAGS="$CACHED_CFLAGS"
104
89# Check for operating system 105# Check for operating system
90AC_MSG_CHECKING([for platform-specific build settings]) 106AC_MSG_CHECKING([for platform-specific build settings])
91case ${host_os} in 107case ${host_os} in
@@ -93,6 +109,7 @@ case ${host_os} in
93 AC_MSG_RESULT([${host_os}]) 109 AC_MSG_RESULT([${host_os}])
94 win32=true 110 win32=true
95 AC_DEFINE(WINVER, 0x0501, [minimum Windows version]) 111 AC_DEFINE(WINVER, 0x0501, [minimum Windows version])
112 deplibs_check_method='pass_all'
96 ;; 113 ;;
97 darwin*) 114 darwin*)
98 AC_MSG_RESULT([${host_os}]) 115 AC_MSG_RESULT([${host_os}])
@@ -107,24 +124,6 @@ esac
107AM_CONDITIONAL(WIN32, test x$win32 = xtrue) 124AM_CONDITIONAL(WIN32, test x$win32 = xtrue)
108AM_CONDITIONAL(DARWIN, test x$darwin = xtrue) 125AM_CONDITIONAL(DARWIN, test x$darwin = xtrue)
109 126
110# Check if the C compiler supports __attribute__((constructor))
111AC_CACHE_CHECK([wether the C compiler supports constructor/destructor attributes],
112 ac_cv_attribute_constructor, [
113 ac_cv_attribute_constructor=no
114 AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
115 [[
116 static void __attribute__((constructor)) test_constructor(void) {
117 }
118 static void __attribute__((destructor)) test_destructor(void) {
119 }
120 ]], [])],
121 [ac_cv_attribute_constructor=yes]
122 )]
123)
124if test "$ac_cv_attribute_constructor" = "yes"; then
125 AC_DEFINE(HAVE_ATTRIBUTE_CONSTRUCTOR, 1, [Define if the C compiler supports constructor/destructor attributes])
126fi
127
128AC_CHECK_MEMBER(struct dirent.d_type, AC_DEFINE(HAVE_DIRENT_D_TYPE, 1, [define if struct dirent has member d_type]),, [#include <dirent.h>]) 127AC_CHECK_MEMBER(struct dirent.d_type, AC_DEFINE(HAVE_DIRENT_D_TYPE, 1, [define if struct dirent has member d_type]),, [#include <dirent.h>])
129 128
130# Cython Python Bindings 129# Cython Python Bindings
diff --git a/cython/debugserver.pxi b/cython/debugserver.pxi
index a3b7d1e..fb96320 100644
--- a/cython/debugserver.pxi
+++ b/cython/debugserver.pxi
@@ -43,13 +43,7 @@ cdef class DebugServerError(BaseError):
43 BaseError.__init__(self, *args, **kwargs) 43 BaseError.__init__(self, *args, **kwargs)
44 44
45 45
46# from http://stackoverflow.com/a/17511714 46from cpython.bytes cimport PyBytes_AsString as PyString_AsString
47# https://github.com/libimobiledevice/libimobiledevice/pull/198
48from cpython cimport PY_MAJOR_VERSION
49if PY_MAJOR_VERSION <= 2:
50 from cpython.string cimport PyString_AsString
51else:
52 from cpython.bytes cimport PyBytes_AsString as PyString_AsString
53cdef char ** to_cstring_array(list_str): 47cdef char ** to_cstring_array(list_str):
54 if not list_str: 48 if not list_str:
55 return NULL 49 return NULL
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 8156d4f..c9b742f 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -21,6 +21,7 @@ man_MANS = \
21 idevicesetlocation.1 \ 21 idevicesetlocation.1 \
22 afcclient.1 22 afcclient.1
23 23
24EXTRA_DIST = $(man_MANS) 24EXTRA_DIST = $(man_MANS) \
25 doxygen
25 26
26DISTCLEANFILES = html/* html 27DISTCLEANFILES = html/* html
diff --git a/docs/doxygen/custom.css b/docs/doxygen/custom.css
index 62183bf..e9f1ea8 100644
--- a/docs/doxygen/custom.css
+++ b/docs/doxygen/custom.css
@@ -230,6 +230,7 @@ div.fragment {
230 border: solid 1px rgb(221, 221, 221); 230 border: solid 1px rgb(221, 221, 221);
231 border-radius: 3px; 231 border-radius: 3px;
232 background-color: rgb(248, 248, 248); 232 background-color: rgb(248, 248, 248);
233 color: rgb(0,0,0);
233} 234}
234 235
235div.line { 236div.line {
@@ -1719,4 +1720,4 @@ th.markdownTableHeadNone {
1719 #projectnumber { 1720 #projectnumber {
1720 font-size: 0.75rem; 1721 font-size: 0.75rem;
1721 } 1722 }
1722} \ No newline at end of file 1723}
diff --git a/docs/idevicecrashreport.1 b/docs/idevicecrashreport.1
index 6acd6e9..f117c87 100644
--- a/docs/idevicecrashreport.1
+++ b/docs/idevicecrashreport.1
@@ -16,28 +16,31 @@ the device to the target DIRECTORY.
16.SH OPTIONS 16.SH OPTIONS
17.TP 17.TP
18.B \-u, \-\-udid UDID 18.B \-u, \-\-udid UDID
19target specific device by UDID. 19Target specific device by UDID.
20.TP 20.TP
21.B \-n, \-\-network 21.B \-n, \-\-network
22connect to network device. 22Connect to network device.
23.TP 23.TP
24.B \-e, \-\-extract 24.B \-e, \-\-extract
25extract raw crash report into separate '.crash' files. 25Extract raw crash report into separate '.crash' files.
26.TP 26.TP
27.B \-k, \-\-keep 27.B \-k, \-\-keep
28copy but do not remove crash reports from device. 28Copy but do not remove crash reports from device.
29.TP 29.TP
30.B \-d, \-\-debug 30.B \-d, \-\-debug
31enable communication debugging. 31Enable communication debugging.
32.TP 32.TP
33.B \-f, \-\-filter NAME 33.B \-f, \-\-filter NAME
34filter crash reports by NAME (case sensitive) 34Filter crash reports by NAME (case sensitive)
35.TP
36.B \-\-remove\-all
37Remove all crash log files without copying. Can be used with \f[B]-f\f[] to only remove matching files.
35.TP 38.TP
36.B \-h, \-\-help 39.B \-h, \-\-help
37prints usage information. 40Prints usage information.
38.TP 41.TP
39.B \-v, \-\-version 42.B \-v, \-\-version
40prints version information. 43Prints version information.
41 44
42.SH AUTHOR 45.SH AUTHOR
43Martin Szulecki 46Martin Szulecki
diff --git a/docs/idevicenotificationproxy.1 b/docs/idevicenotificationproxy.1
index 56dd0b0..627ee5d 100644
--- a/docs/idevicenotificationproxy.1
+++ b/docs/idevicenotificationproxy.1
@@ -12,19 +12,22 @@ Post or observe notifications on an iOS device from the command line.
12.SH OPTIONS 12.SH OPTIONS
13.TP 13.TP
14.B \-u, \-\-udid UDID 14.B \-u, \-\-udid UDID
15target specific device by UDID. 15Target specific device by UDID.
16.TP
17.B \-i, \-\-insecure
18Connect to insecure notification proxy (for non-paired devices).
16.TP 19.TP
17.B \-n, \-\-network 20.B \-n, \-\-network
18connect to network device. 21Connect to network device.
19.TP 22.TP
20.B \-d, \-\-debug 23.B \-d, \-\-debug
21enable communication debugging. 24Enable communication debugging.
22.TP 25.TP
23.B \-h, \-\-help 26.B \-h, \-\-help
24prints usage information. 27Prints usage information.
25.TP 28.TP
26.B \-v, \-\-version 29.B \-v, \-\-version
27prints version information. 30Prints version information.
28 31
29.SH COMMANDS 32.SH COMMANDS
30.TP 33.TP
@@ -38,6 +41,8 @@ observe notification IDs in the foreground until CTRL+C or signal is received.
38 41
39Martin Szulecki 42Martin Szulecki
40 43
44Nikias Bassen
45
41.SH ON THE WEB 46.SH ON THE WEB
42https://libimobiledevice.org 47https://libimobiledevice.org
43 48
diff --git a/docs/idevicesyslog.1 b/docs/idevicesyslog.1
index 66ae2e4..5a677b6 100644
--- a/docs/idevicesyslog.1
+++ b/docs/idevicesyslog.1
@@ -38,13 +38,45 @@ If FILE already exists, it will be overwritten without warning.
38.TP 38.TP
39.B \-\-colors 39.B \-\-colors
40Force writing colored output, e.g. when using \f[B]\-\-output\f[]. 40Force writing colored output, e.g. when using \f[B]\-\-output\f[].
41.TP
42.B \-\-syslog\-relay
43Use old syslog_relay service instead of os_trace_relay (iOS 9+).
44
45.SH COMMANDS
46.TP
47.B pidlist
48Print a list with PID and name of all processes currently running on the device.
49.TP
50.B archive PATH
51Request a logarchive from the device. It will be written in tar format to PATH. To pipe to another process use \- as PATH.
52Below are some options to restrict the log message data.
53
54In order to view the logarchive in a compatible log viewer, you can pipe the output data to \f[B]tar\f[] and have it extract into a new directory:
55
56\f[B]mkdir test.logarchive && tools/idevicesyslog archive - |tar -C test.logarchive -xv\f[]
57
58This will also print the filenames while they are extracted.
59.TP
60Further options for \f[B]archive\f[]:
61.TP
62.B \-\-start\-time VALUE
63Start time of the log data as UNIX timestamp. Earlier messages will be dropped.
64.TP
65.B \-\-age\-limit VALUE
66Maximum age of the log data, supposedly number of days.
67.TP
68.B \-\-size\-limit VALUE
69Limit the size of the archive. The unit is currently unknown, so feel free to experiment.
70.TP
71Keep in mind that the device usually only has a backlog of a few minutes so the options might not have the desired effect. This is not a bug.
41 72
42.SH FILTER OPTIONS 73.SH FILTER OPTIONS
43.TP 74.TP
44.B \-m, \-\-match STRING 75.B \-m, \-\-match STRING
45only print messages that contain STRING 76only print messages that contain STRING
46 77.TP
47This option will set a filter to only printed log messages that contain the given string. 78.B \-M, \-\-unmatch STRING
79print messages that do not contain STRING
48.TP 80.TP
49.B \-t, \-\-trigger STRING 81.B \-t, \-\-trigger STRING
50start logging when matching STRING 82start logging when matching STRING
diff --git a/doxygen.cfg.in b/doxygen.cfg.in
index 4cbbb2d..7bc1160 100644
--- a/doxygen.cfg.in
+++ b/doxygen.cfg.in
@@ -1,4 +1,4 @@
1# Doxyfile 1.8.16 1# Doxyfile 1.11.0
2 2
3# This file describes the settings to be used by the documentation system 3# This file describes the settings to be used by the documentation system
4# doxygen (www.doxygen.org) for a project. 4# doxygen (www.doxygen.org) for a project.
@@ -12,6 +12,16 @@
12# For lists, items can also be appended using: 12# For lists, items can also be appended using:
13# TAG += value [value, ...] 13# TAG += value [value, ...]
14# Values that contain spaces should be placed between quotes (\" \"). 14# Values that contain spaces should be placed between quotes (\" \").
15#
16# Note:
17#
18# Use doxygen to compare the used configuration file with the template
19# configuration file:
20# doxygen -x [configFile]
21# Use doxygen to compare the used configuration file with the template
22# configuration file without replacing the environment variables or CMake type
23# replacement variables:
24# doxygen -x_noenv [configFile]
15 25
16#--------------------------------------------------------------------------- 26#---------------------------------------------------------------------------
17# Project related configuration options 27# Project related configuration options
@@ -53,6 +63,12 @@ PROJECT_BRIEF = "API Documentation"
53 63
54PROJECT_LOGO = docs/doxygen/logo-vector-clean.svg 64PROJECT_LOGO = docs/doxygen/logo-vector-clean.svg
55 65
66# With the PROJECT_ICON tag one can specify an icon that is included in the tabs
67# when the HTML document is shown. Doxygen will copy the logo to the output
68# directory.
69
70PROJECT_ICON =
71
56# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path 72# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
57# into which the generated documentation will be written. If a relative path is 73# into which the generated documentation will be written. If a relative path is
58# entered, it will be relative to the location where doxygen was started. If 74# entered, it will be relative to the location where doxygen was started. If
@@ -60,16 +76,28 @@ PROJECT_LOGO = docs/doxygen/logo-vector-clean.svg
60 76
61OUTPUT_DIRECTORY = docs 77OUTPUT_DIRECTORY = docs
62 78
63# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- 79# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
64# directories (in 2 levels) under the output directory of each output format and 80# sub-directories (in 2 levels) under the output directory of each output format
65# will distribute the generated files over these directories. Enabling this 81# and will distribute the generated files over these directories. Enabling this
66# option can be useful when feeding doxygen a huge amount of source files, where 82# option can be useful when feeding doxygen a huge amount of source files, where
67# putting all generated files in the same directory would otherwise causes 83# putting all generated files in the same directory would otherwise causes
68# performance problems for the file system. 84# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
85# control the number of sub-directories.
69# The default value is: NO. 86# The default value is: NO.
70 87
71CREATE_SUBDIRS = NO 88CREATE_SUBDIRS = NO
72 89
90# Controls the number of sub-directories that will be created when
91# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
92# level increment doubles the number of directories, resulting in 4096
93# directories at level 8 which is the default and also the maximum value. The
94# sub-directories are organized in 2 levels, the first level always has a fixed
95# number of 16 directories.
96# Minimum value: 0, maximum value: 8, default value: 8.
97# This tag requires that the tag CREATE_SUBDIRS is set to YES.
98
99CREATE_SUBDIRS_LEVEL = 8
100
73# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII 101# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
74# characters to appear in the names of generated files. If set to NO, non-ASCII 102# characters to appear in the names of generated files. If set to NO, non-ASCII
75# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode 103# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
@@ -81,14 +109,14 @@ ALLOW_UNICODE_NAMES = NO
81# The OUTPUT_LANGUAGE tag is used to specify the language in which all 109# The OUTPUT_LANGUAGE tag is used to specify the language in which all
82# documentation generated by doxygen is written. Doxygen will use this 110# documentation generated by doxygen is written. Doxygen will use this
83# information to generate all constant output in the proper language. 111# information to generate all constant output in the proper language.
84# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, 112# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
85# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), 113# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
86# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, 114# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
87# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), 115# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
88# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, 116# English messages), Korean, Korean-en (Korean with English messages), Latvian,
89# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, 117# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
90# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, 118# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
91# Ukrainian and Vietnamese. 119# Swedish, Turkish, Ukrainian and Vietnamese.
92# The default value is: English. 120# The default value is: English.
93 121
94OUTPUT_LANGUAGE = English 122OUTPUT_LANGUAGE = English
@@ -209,6 +237,14 @@ QT_AUTOBRIEF = NO
209 237
210MULTILINE_CPP_IS_BRIEF = NO 238MULTILINE_CPP_IS_BRIEF = NO
211 239
240# By default Python docstrings are displayed as preformatted text and doxygen's
241# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
242# doxygen's special commands can be used and the contents of the docstring
243# documentation blocks is shown as doxygen documentation.
244# The default value is: YES.
245
246PYTHON_DOCSTRING = YES
247
212# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the 248# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
213# documentation from any documented member that it re-implements. 249# documentation from any documented member that it re-implements.
214# The default value is: YES. 250# The default value is: YES.
@@ -232,16 +268,16 @@ TAB_SIZE = 8
232# the documentation. An alias has the form: 268# the documentation. An alias has the form:
233# name=value 269# name=value
234# For example adding 270# For example adding
235# "sideeffect=@par Side Effects:\n" 271# "sideeffect=@par Side Effects:^^"
236# will allow you to put the command \sideeffect (or @sideeffect) in the 272# will allow you to put the command \sideeffect (or @sideeffect) in the
237# documentation, which will result in a user-defined paragraph with heading 273# documentation, which will result in a user-defined paragraph with heading
238# "Side Effects:". You can put \n's in the value part of an alias to insert 274# "Side Effects:". Note that you cannot put \n's in the value part of an alias
239# newlines (in the resulting output). You can put ^^ in the value part of an 275# to insert newlines (in the resulting output). You can put ^^ in the value part
240# alias to insert a newline as if a physical newline was in the original file. 276# of an alias to insert a newline as if a physical newline was in the original
241# When you need a literal { or } or , in the value part of an alias you have to 277# file. When you need a literal { or } or , in the value part of an alias you
242# escape them by means of a backslash (\), this can lead to conflicts with the 278# have to escape them by means of a backslash (\), this can lead to conflicts
243# commands \{ and \} for these it is advised to use the version @{ and @} or use 279# with the commands \{ and \} for these it is advised to use the version @{ and
244# a double escape (\\{ and \\}) 280# @} or use a double escape (\\{ and \\})
245 281
246ALIASES = 282ALIASES =
247 283
@@ -285,19 +321,22 @@ OPTIMIZE_OUTPUT_SLICE = YES
285# parses. With this tag you can assign which parser to use for a given 321# parses. With this tag you can assign which parser to use for a given
286# extension. Doxygen has a built-in mapping, but you can override or extend it 322# extension. Doxygen has a built-in mapping, but you can override or extend it
287# using this tag. The format is ext=language, where ext is a file extension, and 323# using this tag. The format is ext=language, where ext is a file extension, and
288# language is one of the parsers supported by doxygen: IDL, Java, Javascript, 324# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
289# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, 325# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
290# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: 326# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
291# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser 327# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
292# tries to guess whether the code is fixed or free formatted code, this is the 328# tries to guess whether the code is fixed or free formatted code, this is the
293# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat 329# default for Fortran type files). For instance to make doxygen treat .inc files
294# .inc files as Fortran files (default is PHP), and .f files as C (default is 330# as Fortran files (default is PHP), and .f files as C (default is Fortran),
295# Fortran), use: inc=Fortran f=C. 331# use: inc=Fortran f=C.
296# 332#
297# Note: For files without extension you can use no_extension as a placeholder. 333# Note: For files without extension you can use no_extension as a placeholder.
298# 334#
299# Note that for custom extensions you also need to set FILE_PATTERNS otherwise 335# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
300# the files are not read by doxygen. 336# the files are not read by doxygen. When specifying no_extension you should add
337# * to the FILE_PATTERNS.
338#
339# Note see also the list of default file extension mappings.
301 340
302EXTENSION_MAPPING = 341EXTENSION_MAPPING =
303 342
@@ -315,11 +354,22 @@ MARKDOWN_SUPPORT = YES
315# to that level are automatically included in the table of contents, even if 354# to that level are automatically included in the table of contents, even if
316# they do not have an id attribute. 355# they do not have an id attribute.
317# Note: This feature currently applies only to Markdown headings. 356# Note: This feature currently applies only to Markdown headings.
318# Minimum value: 0, maximum value: 99, default value: 5. 357# Minimum value: 0, maximum value: 99, default value: 6.
319# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. 358# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
320 359
321TOC_INCLUDE_HEADINGS = 5 360TOC_INCLUDE_HEADINGS = 5
322 361
362# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
363# generate identifiers for the Markdown headings. Note: Every identifier is
364# unique.
365# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
366# sequence number starting at 0 and GITHUB use the lower case version of title
367# with any whitespace replaced by '-' and punctuation characters removed.
368# The default value is: DOXYGEN.
369# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
370
371MARKDOWN_ID_STYLE = DOXYGEN
372
323# When enabled doxygen tries to link words that correspond to documented 373# When enabled doxygen tries to link words that correspond to documented
324# classes, or namespaces to their corresponding documentation. Such a link can 374# classes, or namespaces to their corresponding documentation. Such a link can
325# be prevented in individual cases by putting a % sign in front of the word or 375# be prevented in individual cases by putting a % sign in front of the word or
@@ -332,8 +382,8 @@ AUTOLINK_SUPPORT = YES
332# to include (a tag file for) the STL sources as input, then you should set this 382# to include (a tag file for) the STL sources as input, then you should set this
333# tag to YES in order to let doxygen match functions declarations and 383# tag to YES in order to let doxygen match functions declarations and
334# definitions whose arguments contain STL classes (e.g. func(std::string); 384# definitions whose arguments contain STL classes (e.g. func(std::string);
335# versus func(std::string) {}). This also make the inheritance and collaboration 385# versus func(std::string) {}). This also makes the inheritance and
336# diagrams that involve STL classes more complete and accurate. 386# collaboration diagrams that involve STL classes more complete and accurate.
337# The default value is: NO. 387# The default value is: NO.
338 388
339BUILTIN_STL_SUPPORT = NO 389BUILTIN_STL_SUPPORT = NO
@@ -345,9 +395,9 @@ BUILTIN_STL_SUPPORT = NO
345CPP_CLI_SUPPORT = NO 395CPP_CLI_SUPPORT = NO
346 396
347# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: 397# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
348# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen 398# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse
349# will parse them like normal C++ but will assume all classes use public instead 399# them like normal C++ but will assume all classes use public instead of private
350# of private inheritance when no explicit protection keyword is present. 400# inheritance when no explicit protection keyword is present.
351# The default value is: NO. 401# The default value is: NO.
352 402
353SIP_SUPPORT = NO 403SIP_SUPPORT = NO
@@ -431,6 +481,27 @@ TYPEDEF_HIDES_STRUCT = YES
431 481
432LOOKUP_CACHE_SIZE = 0 482LOOKUP_CACHE_SIZE = 0
433 483
484# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
485# during processing. When set to 0 doxygen will based this on the number of
486# cores available in the system. You can set it explicitly to a value larger
487# than 0 to get more control over the balance between CPU load and processing
488# speed. At this moment only the input processing can be done using multiple
489# threads. Since this is still an experimental feature the default is set to 1,
490# which effectively disables parallel processing. Please report any issues you
491# encounter. Generating dot graphs in parallel is controlled by the
492# DOT_NUM_THREADS setting.
493# Minimum value: 0, maximum value: 32, default value: 1.
494
495NUM_PROC_THREADS = 1
496
497# If the TIMESTAMP tag is set different from NO then each generated page will
498# contain the date or date and time when the page was generated. Setting this to
499# NO can help when comparing the output of multiple runs.
500# Possible values are: YES, NO, DATETIME and DATE.
501# The default value is: NO.
502
503TIMESTAMP = YES
504
434#--------------------------------------------------------------------------- 505#---------------------------------------------------------------------------
435# Build related configuration options 506# Build related configuration options
436#--------------------------------------------------------------------------- 507#---------------------------------------------------------------------------
@@ -494,6 +565,13 @@ EXTRACT_LOCAL_METHODS = NO
494 565
495EXTRACT_ANON_NSPACES = NO 566EXTRACT_ANON_NSPACES = NO
496 567
568# If this flag is set to YES, the name of an unnamed parameter in a declaration
569# will be determined by the corresponding definition. By default unnamed
570# parameters remain unnamed in the output.
571# The default value is: YES.
572
573RESOLVE_UNNAMED_PARAMS = YES
574
497# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all 575# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
498# undocumented members inside documented classes or files. If set to NO these 576# undocumented members inside documented classes or files. If set to NO these
499# members will be included in the various overviews, but no documentation 577# members will be included in the various overviews, but no documentation
@@ -505,14 +583,15 @@ HIDE_UNDOC_MEMBERS = NO
505# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all 583# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
506# undocumented classes that are normally visible in the class hierarchy. If set 584# undocumented classes that are normally visible in the class hierarchy. If set
507# to NO, these classes will be included in the various overviews. This option 585# to NO, these classes will be included in the various overviews. This option
508# has no effect if EXTRACT_ALL is enabled. 586# will also hide undocumented C++ concepts if enabled. This option has no effect
587# if EXTRACT_ALL is enabled.
509# The default value is: NO. 588# The default value is: NO.
510 589
511HIDE_UNDOC_CLASSES = NO 590HIDE_UNDOC_CLASSES = NO
512 591
513# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend 592# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
514# (class|struct|union) declarations. If set to NO, these declarations will be 593# declarations. If set to NO, these declarations will be included in the
515# included in the documentation. 594# documentation.
516# The default value is: NO. 595# The default value is: NO.
517 596
518HIDE_FRIEND_COMPOUNDS = NO 597HIDE_FRIEND_COMPOUNDS = NO
@@ -531,12 +610,20 @@ HIDE_IN_BODY_DOCS = NO
531 610
532INTERNAL_DOCS = NO 611INTERNAL_DOCS = NO
533 612
534# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file 613# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
535# names in lower-case letters. If set to YES, upper-case letters are also 614# able to match the capabilities of the underlying filesystem. In case the
536# allowed. This is useful if you have classes or files whose names only differ 615# filesystem is case sensitive (i.e. it supports files in the same directory
537# in case and if your file system supports case sensitive file names. Windows 616# whose names only differ in casing), the option must be set to YES to properly
538# (including Cygwin) ands Mac users are advised to set this option to NO. 617# deal with such files in case they appear in the input. For filesystems that
539# The default value is: system dependent. 618# are not case sensitive the option should be set to NO to properly deal with
619# output files written for symbols that only differ in casing, such as for two
620# classes, one named CLASS and the other named Class, and to also support
621# references to files without having to specify the exact matching casing. On
622# Windows (including Cygwin) and MacOS, users should typically set this option
623# to NO, whereas on Linux or other Unix flavors it should typically be set to
624# YES.
625# Possible values are: SYSTEM, NO and YES.
626# The default value is: SYSTEM.
540 627
541CASE_SENSE_NAMES = NO 628CASE_SENSE_NAMES = NO
542 629
@@ -554,6 +641,12 @@ HIDE_SCOPE_NAMES = NO
554 641
555HIDE_COMPOUND_REFERENCE= NO 642HIDE_COMPOUND_REFERENCE= NO
556 643
644# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
645# will show which file needs to be included to use the class.
646# The default value is: YES.
647
648SHOW_HEADERFILE = YES
649
557# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of 650# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
558# the files that are included by a file in the documentation of that file. 651# the files that are included by a file in the documentation of that file.
559# The default value is: YES. 652# The default value is: YES.
@@ -711,7 +804,8 @@ FILE_VERSION_FILTER =
711# output files in an output format independent way. To create the layout file 804# output files in an output format independent way. To create the layout file
712# that represents doxygen's defaults, run doxygen with the -l option. You can 805# that represents doxygen's defaults, run doxygen with the -l option. You can
713# optionally specify a file name after the option, if omitted DoxygenLayout.xml 806# optionally specify a file name after the option, if omitted DoxygenLayout.xml
714# will be used as the name of the layout file. 807# will be used as the name of the layout file. See also section "Changing the
808# layout of pages" for information.
715# 809#
716# Note that if you run doxygen from a directory containing a file called 810# Note that if you run doxygen from a directory containing a file called
717# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE 811# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
@@ -757,24 +851,50 @@ WARNINGS = YES
757WARN_IF_UNDOCUMENTED = YES 851WARN_IF_UNDOCUMENTED = YES
758 852
759# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for 853# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
760# potential errors in the documentation, such as not documenting some parameters 854# potential errors in the documentation, such as documenting some parameters in
761# in a documented function, or documenting parameters that don't exist or using 855# a documented function twice, or documenting parameters that don't exist or
762# markup commands wrongly. 856# using markup commands wrongly.
763# The default value is: YES. 857# The default value is: YES.
764 858
765WARN_IF_DOC_ERROR = YES 859WARN_IF_DOC_ERROR = YES
766 860
861# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
862# function parameter documentation. If set to NO, doxygen will accept that some
863# parameters have no documentation without warning.
864# The default value is: YES.
865
866WARN_IF_INCOMPLETE_DOC = YES
867
767# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that 868# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
768# are documented, but have no documentation for their parameters or return 869# are documented, but have no documentation for their parameters or return
769# value. If set to NO, doxygen will only warn about wrong or incomplete 870# value. If set to NO, doxygen will only warn about wrong parameter
770# parameter documentation, but not about the absence of documentation. If 871# documentation, but not about the absence of documentation. If EXTRACT_ALL is
771# EXTRACT_ALL is set to YES then this flag will automatically be disabled. 872# set to YES then this flag will automatically be disabled. See also
873# WARN_IF_INCOMPLETE_DOC
772# The default value is: NO. 874# The default value is: NO.
773 875
774WARN_NO_PARAMDOC = NO 876WARN_NO_PARAMDOC = NO
775 877
878# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
879# undocumented enumeration values. If set to NO, doxygen will accept
880# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
881# will automatically be disabled.
882# The default value is: NO.
883
884WARN_IF_UNDOC_ENUM_VAL = NO
885
776# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when 886# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
777# a warning is encountered. 887# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
888# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
889# at the end of the doxygen process doxygen will return with a non-zero status.
890# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
891# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
892# write the warning messages in between other messages but write them at the end
893# of a run, in case a WARN_LOGFILE is defined the warning messages will be
894# besides being in the defined file also be shown at the end of a run, unless
895# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
896# the behavior will remain as with the setting FAIL_ON_WARNINGS.
897# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
778# The default value is: NO. 898# The default value is: NO.
779 899
780WARN_AS_ERROR = NO 900WARN_AS_ERROR = NO
@@ -785,13 +905,27 @@ WARN_AS_ERROR = NO
785# and the warning text. Optionally the format may contain $version, which will 905# and the warning text. Optionally the format may contain $version, which will
786# be replaced by the version of the file (if it could be obtained via 906# be replaced by the version of the file (if it could be obtained via
787# FILE_VERSION_FILTER) 907# FILE_VERSION_FILTER)
908# See also: WARN_LINE_FORMAT
788# The default value is: $file:$line: $text. 909# The default value is: $file:$line: $text.
789 910
790WARN_FORMAT = "$file:$line: $text" 911WARN_FORMAT = "$file:$line: $text"
791 912
913# In the $text part of the WARN_FORMAT command it is possible that a reference
914# to a more specific place is given. To make it easier to jump to this place
915# (outside of doxygen) the user can define a custom "cut" / "paste" string.
916# Example:
917# WARN_LINE_FORMAT = "'vi $file +$line'"
918# See also: WARN_FORMAT
919# The default value is: at line $line of file $file.
920
921WARN_LINE_FORMAT = "at line $line of file $file"
922
792# The WARN_LOGFILE tag can be used to specify a file to which warning and error 923# The WARN_LOGFILE tag can be used to specify a file to which warning and error
793# messages should be written. If left blank the output is written to standard 924# messages should be written. If left blank the output is written to standard
794# error (stderr). 925# error (stderr). In case the file specified cannot be opened for writing the
926# warning and error messages are written to standard error. When as file - is
927# specified the warning and error messages are written to standard output
928# (stdout).
795 929
796WARN_LOGFILE = 930WARN_LOGFILE =
797 931
@@ -805,19 +939,29 @@ WARN_LOGFILE =
805# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING 939# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
806# Note: If this tag is empty the current directory is searched. 940# Note: If this tag is empty the current directory is searched.
807 941
808INPUT = \ 942INPUT = include/@PACKAGE@ \
809 include/@PACKAGE@ \ 943 README.md
810 README.md
811 944
812# This tag can be used to specify the character encoding of the source files 945# This tag can be used to specify the character encoding of the source files
813# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses 946# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
814# libiconv (or the iconv built into libc) for the transcoding. See the libiconv 947# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
815# documentation (see: https://www.gnu.org/software/libiconv/) for the list of 948# documentation (see:
816# possible encodings. 949# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
950# See also: INPUT_FILE_ENCODING
817# The default value is: UTF-8. 951# The default value is: UTF-8.
818 952
819INPUT_ENCODING = UTF-8 953INPUT_ENCODING = UTF-8
820 954
955# This tag can be used to specify the character encoding of the source files
956# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
957# character encoding on a per file pattern basis. Doxygen will compare the file
958# name with each pattern and apply the encoding instead of the default
959# INPUT_ENCODING) if there is a match. The character encodings are a list of the
960# form: pattern=encoding (like *.php=ISO-8859-1).
961# See also: INPUT_ENCODING for further information on supported encodings.
962
963INPUT_FILE_ENCODING =
964
821# If the value of the INPUT tag contains directories, you can use the 965# If the value of the INPUT tag contains directories, you can use the
822# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and 966# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
823# *.h) to filter out the source-files in the directories. 967# *.h) to filter out the source-files in the directories.
@@ -826,11 +970,15 @@ INPUT_ENCODING = UTF-8
826# need to set EXTENSION_MAPPING for the extension otherwise the files are not 970# need to set EXTENSION_MAPPING for the extension otherwise the files are not
827# read by doxygen. 971# read by doxygen.
828# 972#
829# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, 973# Note the list of default checked file patterns might differ from the list of
830# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, 974# default file extension mappings.
831# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, 975#
832# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, 976# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
833# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. 977# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl,
978# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d,
979# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to
980# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
981# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
834 982
835FILE_PATTERNS = 983FILE_PATTERNS =
836 984
@@ -869,10 +1017,7 @@ EXCLUDE_PATTERNS =
869# (namespaces, classes, functions, etc.) that should be excluded from the 1017# (namespaces, classes, functions, etc.) that should be excluded from the
870# output. The symbol name can be a fully qualified name, a word, or if the 1018# output. The symbol name can be a fully qualified name, a word, or if the
871# wildcard * is used, a substring. Examples: ANamespace, AClass, 1019# wildcard * is used, a substring. Examples: ANamespace, AClass,
872# AClass::ANamespace, ANamespace::*Test 1020# ANamespace::AClass, ANamespace::*Test
873#
874# Note that the wildcards are matched against the file with absolute path, so to
875# exclude all test directories use the pattern */test/*
876 1021
877EXCLUDE_SYMBOLS = LIBIMOBILEDEVICE_API 1022EXCLUDE_SYMBOLS = LIBIMOBILEDEVICE_API
878 1023
@@ -917,6 +1062,11 @@ IMAGE_PATH =
917# code is scanned, but not when the output code is generated. If lines are added 1062# code is scanned, but not when the output code is generated. If lines are added
918# or removed, the anchors will not be placed correctly. 1063# or removed, the anchors will not be placed correctly.
919# 1064#
1065# Note that doxygen will use the data processed and written to standard output
1066# for further processing, therefore nothing else, like debug statements or used
1067# commands (so in case of a Windows batch file always use @echo OFF), should be
1068# written to standard output.
1069#
920# Note that for custom extensions or not directly supported extensions you also 1070# Note that for custom extensions or not directly supported extensions you also
921# need to set EXTENSION_MAPPING for the extension otherwise the files are not 1071# need to set EXTENSION_MAPPING for the extension otherwise the files are not
922# properly processed by doxygen. 1072# properly processed by doxygen.
@@ -958,6 +1108,15 @@ FILTER_SOURCE_PATTERNS =
958 1108
959USE_MDFILE_AS_MAINPAGE = README.md 1109USE_MDFILE_AS_MAINPAGE = README.md
960 1110
1111# The Fortran standard specifies that for fixed formatted Fortran code all
1112# characters from position 72 are to be considered as comment. A common
1113# extension is to allow longer lines before the automatic comment starts. The
1114# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
1115# be processed before the automatic comment starts.
1116# Minimum value: 7, maximum value: 10000, default value: 72.
1117
1118FORTRAN_COMMENT_AFTER = 72
1119
961#--------------------------------------------------------------------------- 1120#---------------------------------------------------------------------------
962# Configuration options related to source browsing 1121# Configuration options related to source browsing
963#--------------------------------------------------------------------------- 1122#---------------------------------------------------------------------------
@@ -972,7 +1131,8 @@ USE_MDFILE_AS_MAINPAGE = README.md
972SOURCE_BROWSER = NO 1131SOURCE_BROWSER = NO
973 1132
974# Setting the INLINE_SOURCES tag to YES will include the body of functions, 1133# Setting the INLINE_SOURCES tag to YES will include the body of functions,
975# classes and enums directly into the documentation. 1134# multi-line macros, enums or list initialized variables directly into the
1135# documentation.
976# The default value is: NO. 1136# The default value is: NO.
977 1137
978INLINE_SOURCES = NO 1138INLINE_SOURCES = NO
@@ -1055,10 +1215,11 @@ VERBATIM_HEADERS = NO
1055 1215
1056ALPHABETICAL_INDEX = NO 1216ALPHABETICAL_INDEX = NO
1057 1217
1058# In case all classes in a project start with a common prefix, all classes will 1218# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
1059# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag 1219# that should be ignored while generating the index headers. The IGNORE_PREFIX
1060# can be used to specify a prefix (or a list of prefixes) that should be ignored 1220# tag works for classes, function and member names. The entity will be placed in
1061# while generating the index headers. 1221# the alphabetical list under the first letter of the entity name that remains
1222# after removing the prefix.
1062# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. 1223# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
1063 1224
1064IGNORE_PREFIX = 1225IGNORE_PREFIX =
@@ -1137,11 +1298,15 @@ HTML_STYLESHEET =
1137# Doxygen will copy the style sheet files to the output directory. 1298# Doxygen will copy the style sheet files to the output directory.
1138# Note: The order of the extra style sheet files is of importance (e.g. the last 1299# Note: The order of the extra style sheet files is of importance (e.g. the last
1139# style sheet in the list overrules the setting of the previous ones in the 1300# style sheet in the list overrules the setting of the previous ones in the
1140# list). For an example see the documentation. 1301# list).
1302# Note: Since the styling of scrollbars can currently not be overruled in
1303# Webkit/Chromium, the styling will be left out of the default doxygen.css if
1304# one or more extra stylesheets have been specified. So if scrollbar
1305# customization is desired it has to be added explicitly. For an example see the
1306# documentation.
1141# This tag requires that the tag GENERATE_HTML is set to YES. 1307# This tag requires that the tag GENERATE_HTML is set to YES.
1142 1308
1143HTML_EXTRA_STYLESHEET = \ 1309HTML_EXTRA_STYLESHEET = docs/doxygen/custom.css
1144 docs/doxygen/custom.css
1145 1310
1146# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 1311# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
1147# other source files which should be copied to the HTML output directory. Note 1312# other source files which should be copied to the HTML output directory. Note
@@ -1151,15 +1316,27 @@ HTML_EXTRA_STYLESHEET = \
1151# files will be copied as-is; there are no commands or markers available. 1316# files will be copied as-is; there are no commands or markers available.
1152# This tag requires that the tag GENERATE_HTML is set to YES. 1317# This tag requires that the tag GENERATE_HTML is set to YES.
1153 1318
1154HTML_EXTRA_FILES = \ 1319HTML_EXTRA_FILES = docs/doxygen/favicon.ico \
1155 docs/doxygen/favicon.ico \ 1320 docs/doxygen/folder.png \
1156 docs/doxygen/folder.png \ 1321 docs/doxygen/folder-open.png \
1157 docs/doxygen/folder-open.png \ 1322 docs/doxygen/text-x-generic.png
1158 docs/doxygen/text-x-generic.png 1323
1324# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
1325# should be rendered with a dark or light theme.
1326# Possible values are: LIGHT always generates light mode output, DARK always
1327# generates dark mode output, AUTO_LIGHT automatically sets the mode according
1328# to the user preference, uses light mode if no preference is set (the default),
1329# AUTO_DARK automatically sets the mode according to the user preference, uses
1330# dark mode if no preference is set and TOGGLE allows a user to switch between
1331# light and dark mode via a button.
1332# The default value is: AUTO_LIGHT.
1333# This tag requires that the tag GENERATE_HTML is set to YES.
1334
1335HTML_COLORSTYLE = AUTO_LIGHT
1159 1336
1160# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen 1337# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
1161# will adjust the colors in the style sheet and background images according to 1338# will adjust the colors in the style sheet and background images according to
1162# this color. Hue is specified as an angle on a colorwheel, see 1339# this color. Hue is specified as an angle on a color-wheel, see
1163# https://en.wikipedia.org/wiki/Hue for more information. For instance the value 1340# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
1164# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 1341# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
1165# purple, and 360 is red again. 1342# purple, and 360 is red again.
@@ -1169,7 +1346,7 @@ HTML_EXTRA_FILES = \
1169HTML_COLORSTYLE_HUE = 220 1346HTML_COLORSTYLE_HUE = 220
1170 1347
1171# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors 1348# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
1172# in the HTML output. For a value of 0 the output will use grayscales only. A 1349# in the HTML output. For a value of 0 the output will use gray-scales only. A
1173# value of 255 will produce the most vivid colors. 1350# value of 255 will produce the most vivid colors.
1174# Minimum value: 0, maximum value: 255, default value: 100. 1351# Minimum value: 0, maximum value: 255, default value: 100.
1175# This tag requires that the tag GENERATE_HTML is set to YES. 1352# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1187,20 +1364,11 @@ HTML_COLORSTYLE_SAT = 100
1187 1364
1188HTML_COLORSTYLE_GAMMA = 80 1365HTML_COLORSTYLE_GAMMA = 80
1189 1366
1190# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
1191# page will contain the date and time when the page was generated. Setting this
1192# to YES can help to show when doxygen was last run and thus if the
1193# documentation is up to date.
1194# The default value is: NO.
1195# This tag requires that the tag GENERATE_HTML is set to YES.
1196
1197HTML_TIMESTAMP = YES
1198
1199# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML 1367# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
1200# documentation will contain a main index with vertical navigation menus that 1368# documentation will contain a main index with vertical navigation menus that
1201# are dynamically created via Javascript. If disabled, the navigation index will 1369# are dynamically created via JavaScript. If disabled, the navigation index will
1202# consists of multiple levels of tabs that are statically embedded in every HTML 1370# consists of multiple levels of tabs that are statically embedded in every HTML
1203# page. Disable this option to support browsers that do not have Javascript, 1371# page. Disable this option to support browsers that do not have JavaScript,
1204# like the Qt help browser. 1372# like the Qt help browser.
1205# The default value is: YES. 1373# The default value is: YES.
1206# This tag requires that the tag GENERATE_HTML is set to YES. 1374# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1215,6 +1383,33 @@ HTML_DYNAMIC_MENUS = NO
1215 1383
1216HTML_DYNAMIC_SECTIONS = NO 1384HTML_DYNAMIC_SECTIONS = NO
1217 1385
1386# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
1387# dynamically folded and expanded in the generated HTML source code.
1388# The default value is: YES.
1389# This tag requires that the tag GENERATE_HTML is set to YES.
1390
1391HTML_CODE_FOLDING = YES
1392
1393# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in
1394# the top right corner of code and text fragments that allows the user to copy
1395# its content to the clipboard. Note this only works if supported by the browser
1396# and the web page is served via a secure context (see:
1397# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file:
1398# protocol.
1399# The default value is: YES.
1400# This tag requires that the tag GENERATE_HTML is set to YES.
1401
1402HTML_COPY_CLIPBOARD = YES
1403
1404# Doxygen stores a couple of settings persistently in the browser (via e.g.
1405# cookies). By default these settings apply to all HTML pages generated by
1406# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store
1407# the settings under a project specific key, such that the user preferences will
1408# be stored separately.
1409# This tag requires that the tag GENERATE_HTML is set to YES.
1410
1411HTML_PROJECT_COOKIE =
1412
1218# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries 1413# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
1219# shown in the various tree structured indices initially; the user can expand 1414# shown in the various tree structured indices initially; the user can expand
1220# and collapse entries dynamically later on. Doxygen will expand the tree to 1415# and collapse entries dynamically later on. Doxygen will expand the tree to
@@ -1230,10 +1425,11 @@ HTML_INDEX_NUM_ENTRIES = 100
1230 1425
1231# If the GENERATE_DOCSET tag is set to YES, additional index files will be 1426# If the GENERATE_DOCSET tag is set to YES, additional index files will be
1232# generated that can be used as input for Apple's Xcode 3 integrated development 1427# generated that can be used as input for Apple's Xcode 3 integrated development
1233# environment (see: https://developer.apple.com/xcode/), introduced with OSX 1428# environment (see:
1234# 10.5 (Leopard). To create a documentation set, doxygen will generate a 1429# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
1235# Makefile in the HTML output directory. Running make will produce the docset in 1430# create a documentation set, doxygen will generate a Makefile in the HTML
1236# that directory and running make install will install the docset in 1431# output directory. Running make will produce the docset in that directory and
1432# running make install will install the docset in
1237# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at 1433# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
1238# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy 1434# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
1239# genXcode/_index.html for more information. 1435# genXcode/_index.html for more information.
@@ -1250,6 +1446,13 @@ GENERATE_DOCSET = NO
1250 1446
1251DOCSET_FEEDNAME = "Doxygen generated docs" 1447DOCSET_FEEDNAME = "Doxygen generated docs"
1252 1448
1449# This tag determines the URL of the docset feed. A documentation feed provides
1450# an umbrella under which multiple documentation sets from a single provider
1451# (such as a company or product suite) can be grouped.
1452# This tag requires that the tag GENERATE_DOCSET is set to YES.
1453
1454DOCSET_FEEDURL =
1455
1253# This tag specifies a string that should uniquely identify the documentation 1456# This tag specifies a string that should uniquely identify the documentation
1254# set bundle. This should be a reverse domain-name style string, e.g. 1457# set bundle. This should be a reverse domain-name style string, e.g.
1255# com.mycompany.MyDocSet. Doxygen will append .docset to the name. 1458# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
@@ -1275,8 +1478,12 @@ DOCSET_PUBLISHER_NAME = Publisher
1275# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three 1478# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
1276# additional HTML index files: index.hhp, index.hhc, and index.hhk. The 1479# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
1277# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop 1480# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
1278# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on 1481# on Windows. In the beginning of 2021 Microsoft took the original page, with
1279# Windows. 1482# a.o. the download links, offline the HTML help workshop was already many years
1483# in maintenance mode). You can download the HTML help workshop from the web
1484# archives at Installation executable (see:
1485# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
1486# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
1280# 1487#
1281# The HTML Help Workshop contains a compiler that can convert all HTML output 1488# The HTML Help Workshop contains a compiler that can convert all HTML output
1282# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML 1489# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
@@ -1306,7 +1513,7 @@ CHM_FILE =
1306HHC_LOCATION = 1513HHC_LOCATION =
1307 1514
1308# The GENERATE_CHI flag controls if a separate .chi index file is generated 1515# The GENERATE_CHI flag controls if a separate .chi index file is generated
1309# (YES) or that it should be included in the master .chm file (NO). 1516# (YES) or that it should be included in the main .chm file (NO).
1310# The default value is: NO. 1517# The default value is: NO.
1311# This tag requires that the tag GENERATE_HTMLHELP is set to YES. 1518# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
1312 1519
@@ -1333,6 +1540,16 @@ BINARY_TOC = NO
1333 1540
1334TOC_EXPAND = NO 1541TOC_EXPAND = NO
1335 1542
1543# The SITEMAP_URL tag is used to specify the full URL of the place where the
1544# generated documentation will be placed on the server by the user during the
1545# deployment of the documentation. The generated sitemap is called sitemap.xml
1546# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
1547# is specified no sitemap is generated. For information about the sitemap
1548# protocol see https://www.sitemaps.org
1549# This tag requires that the tag GENERATE_HTML is set to YES.
1550
1551SITEMAP_URL =
1552
1336# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 1553# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
1337# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that 1554# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
1338# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help 1555# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
@@ -1351,7 +1568,8 @@ QCH_FILE =
1351 1568
1352# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help 1569# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
1353# Project output. For more information please see Qt Help Project / Namespace 1570# Project output. For more information please see Qt Help Project / Namespace
1354# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). 1571# (see:
1572# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
1355# The default value is: org.doxygen.Project. 1573# The default value is: org.doxygen.Project.
1356# This tag requires that the tag GENERATE_QHP is set to YES. 1574# This tag requires that the tag GENERATE_QHP is set to YES.
1357 1575
@@ -1359,8 +1577,8 @@ QHP_NAMESPACE = org.doxygen.Project
1359 1577
1360# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt 1578# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
1361# Help Project output. For more information please see Qt Help Project / Virtual 1579# Help Project output. For more information please see Qt Help Project / Virtual
1362# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- 1580# Folders (see:
1363# folders). 1581# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
1364# The default value is: doc. 1582# The default value is: doc.
1365# This tag requires that the tag GENERATE_QHP is set to YES. 1583# This tag requires that the tag GENERATE_QHP is set to YES.
1366 1584
@@ -1368,16 +1586,16 @@ QHP_VIRTUAL_FOLDER = doc
1368 1586
1369# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom 1587# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
1370# filter to add. For more information please see Qt Help Project / Custom 1588# filter to add. For more information please see Qt Help Project / Custom
1371# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- 1589# Filters (see:
1372# filters). 1590# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
1373# This tag requires that the tag GENERATE_QHP is set to YES. 1591# This tag requires that the tag GENERATE_QHP is set to YES.
1374 1592
1375QHP_CUST_FILTER_NAME = 1593QHP_CUST_FILTER_NAME =
1376 1594
1377# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the 1595# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
1378# custom filter to add. For more information please see Qt Help Project / Custom 1596# custom filter to add. For more information please see Qt Help Project / Custom
1379# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- 1597# Filters (see:
1380# filters). 1598# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
1381# This tag requires that the tag GENERATE_QHP is set to YES. 1599# This tag requires that the tag GENERATE_QHP is set to YES.
1382 1600
1383QHP_CUST_FILTER_ATTRS = 1601QHP_CUST_FILTER_ATTRS =
@@ -1389,9 +1607,9 @@ QHP_CUST_FILTER_ATTRS =
1389 1607
1390QHP_SECT_FILTER_ATTRS = 1608QHP_SECT_FILTER_ATTRS =
1391 1609
1392# The QHG_LOCATION tag can be used to specify the location of Qt's 1610# The QHG_LOCATION tag can be used to specify the location (absolute path
1393# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the 1611# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
1394# generated .qhp file. 1612# run qhelpgenerator on the generated .qhp file.
1395# This tag requires that the tag GENERATE_QHP is set to YES. 1613# This tag requires that the tag GENERATE_QHP is set to YES.
1396 1614
1397QHG_LOCATION = 1615QHG_LOCATION =
@@ -1434,16 +1652,28 @@ DISABLE_INDEX = NO
1434# to work a browser that supports JavaScript, DHTML, CSS and frames is required 1652# to work a browser that supports JavaScript, DHTML, CSS and frames is required
1435# (i.e. any modern browser). Windows users are probably better off using the 1653# (i.e. any modern browser). Windows users are probably better off using the
1436# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can 1654# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
1437# further fine-tune the look of the index. As an example, the default style 1655# further fine tune the look of the index (see "Fine-tuning the output"). As an
1438# sheet generated by doxygen has an example that shows how to put an image at 1656# example, the default style sheet generated by doxygen has an example that
1439# the root of the tree instead of the PROJECT_NAME. Since the tree basically has 1657# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
1440# the same information as the tab index, you could consider setting 1658# Since the tree basically has the same information as the tab index, you could
1441# DISABLE_INDEX to YES when enabling this option. 1659# consider setting DISABLE_INDEX to YES when enabling this option.
1442# The default value is: NO. 1660# The default value is: NO.
1443# This tag requires that the tag GENERATE_HTML is set to YES. 1661# This tag requires that the tag GENERATE_HTML is set to YES.
1444 1662
1445GENERATE_TREEVIEW = NONE 1663GENERATE_TREEVIEW = NONE
1446 1664
1665# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
1666# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
1667# area (value NO) or if it should extend to the full height of the window (value
1668# YES). Setting this to YES gives a layout similar to
1669# https://docs.readthedocs.io with more room for contents, but less room for the
1670# project logo, title, and description. If either GENERATE_TREEVIEW or
1671# DISABLE_INDEX is set to NO, this option has no effect.
1672# The default value is: NO.
1673# This tag requires that the tag GENERATE_HTML is set to YES.
1674
1675FULL_SIDEBAR = NO
1676
1447# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that 1677# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
1448# doxygen will group on one line in the generated HTML documentation. 1678# doxygen will group on one line in the generated HTML documentation.
1449# 1679#
@@ -1468,6 +1698,24 @@ TREEVIEW_WIDTH = 250
1468 1698
1469EXT_LINKS_IN_WINDOW = NO 1699EXT_LINKS_IN_WINDOW = NO
1470 1700
1701# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
1702# addresses.
1703# The default value is: YES.
1704# This tag requires that the tag GENERATE_HTML is set to YES.
1705
1706OBFUSCATE_EMAILS = YES
1707
1708# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
1709# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
1710# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
1711# the HTML output. These images will generally look nicer at scaled resolutions.
1712# Possible values are: png (the default) and svg (looks nicer but requires the
1713# pdf2svg or inkscape tool).
1714# The default value is: png.
1715# This tag requires that the tag GENERATE_HTML is set to YES.
1716
1717HTML_FORMULA_FORMAT = png
1718
1471# Use this tag to change the font size of LaTeX formulas included as images in 1719# Use this tag to change the font size of LaTeX formulas included as images in
1472# the HTML documentation. When you change the font size after a successful 1720# the HTML documentation. When you change the font size after a successful
1473# doxygen run you need to manually remove any form_*.png images from the HTML 1721# doxygen run you need to manually remove any form_*.png images from the HTML
@@ -1477,19 +1725,14 @@ EXT_LINKS_IN_WINDOW = NO
1477 1725
1478FORMULA_FONTSIZE = 10 1726FORMULA_FONTSIZE = 10
1479 1727
1480# Use the FORMULA_TRANSPARENT tag to determine whether or not the images 1728# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
1481# generated for formulas are transparent PNGs. Transparent PNGs are not 1729# to create new LaTeX commands to be used in formulas as building blocks. See
1482# supported properly for IE 6.0, but are supported on all modern browsers. 1730# the section "Including formulas" for details.
1483#
1484# Note that when changing this option you need to delete any form_*.png files in
1485# the HTML output directory before the changes have effect.
1486# The default value is: YES.
1487# This tag requires that the tag GENERATE_HTML is set to YES.
1488 1731
1489FORMULA_TRANSPARENT = YES 1732FORMULA_MACROFILE =
1490 1733
1491# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see 1734# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
1492# https://www.mathjax.org) which uses client side Javascript for the rendering 1735# https://www.mathjax.org) which uses client side JavaScript for the rendering
1493# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX 1736# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
1494# installed or if you want to formulas look prettier in the HTML output. When 1737# installed or if you want to formulas look prettier in the HTML output. When
1495# enabled you may also need to install MathJax separately and configure the path 1738# enabled you may also need to install MathJax separately and configure the path
@@ -1499,11 +1742,29 @@ FORMULA_TRANSPARENT = YES
1499 1742
1500USE_MATHJAX = NO 1743USE_MATHJAX = NO
1501 1744
1745# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
1746# Note that the different versions of MathJax have different requirements with
1747# regards to the different settings, so it is possible that also other MathJax
1748# settings have to be changed when switching between the different MathJax
1749# versions.
1750# Possible values are: MathJax_2 and MathJax_3.
1751# The default value is: MathJax_2.
1752# This tag requires that the tag USE_MATHJAX is set to YES.
1753
1754MATHJAX_VERSION = MathJax_2
1755
1502# When MathJax is enabled you can set the default output format to be used for 1756# When MathJax is enabled you can set the default output format to be used for
1503# the MathJax output. See the MathJax site (see: 1757# the MathJax output. For more details about the output format see MathJax
1504# http://docs.mathjax.org/en/latest/output.html) for more details. 1758# version 2 (see:
1759# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
1760# (see:
1761# http://docs.mathjax.org/en/latest/web/components/output.html).
1505# Possible values are: HTML-CSS (which is slower, but has the best 1762# Possible values are: HTML-CSS (which is slower, but has the best
1506# compatibility), NativeMML (i.e. MathML) and SVG. 1763# compatibility. This is the name for Mathjax version 2, for MathJax version 3
1764# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
1765# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
1766# is the name for Mathjax version 3, for MathJax version 2 this will be
1767# translated into HTML-CSS) and SVG.
1507# The default value is: HTML-CSS. 1768# The default value is: HTML-CSS.
1508# This tag requires that the tag USE_MATHJAX is set to YES. 1769# This tag requires that the tag USE_MATHJAX is set to YES.
1509 1770
@@ -1516,22 +1777,29 @@ MATHJAX_FORMAT = HTML-CSS
1516# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax 1777# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
1517# Content Delivery Network so you can quickly see the result without installing 1778# Content Delivery Network so you can quickly see the result without installing
1518# MathJax. However, it is strongly recommended to install a local copy of 1779# MathJax. However, it is strongly recommended to install a local copy of
1519# MathJax from https://www.mathjax.org before deployment. 1780# MathJax from https://www.mathjax.org before deployment. The default value is:
1520# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. 1781# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
1782# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
1521# This tag requires that the tag USE_MATHJAX is set to YES. 1783# This tag requires that the tag USE_MATHJAX is set to YES.
1522 1784
1523MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest 1785MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
1524 1786
1525# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax 1787# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
1526# extension names that should be enabled during MathJax rendering. For example 1788# extension names that should be enabled during MathJax rendering. For example
1789# for MathJax version 2 (see
1790# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
1527# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols 1791# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
1792# For example for MathJax version 3 (see
1793# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
1794# MATHJAX_EXTENSIONS = ams
1528# This tag requires that the tag USE_MATHJAX is set to YES. 1795# This tag requires that the tag USE_MATHJAX is set to YES.
1529 1796
1530MATHJAX_EXTENSIONS = 1797MATHJAX_EXTENSIONS =
1531 1798
1532# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces 1799# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
1533# of code that will be used on startup of the MathJax code. See the MathJax site 1800# of code that will be used on startup of the MathJax code. See the MathJax site
1534# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an 1801# (see:
1802# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
1535# example see the documentation. 1803# example see the documentation.
1536# This tag requires that the tag USE_MATHJAX is set to YES. 1804# This tag requires that the tag USE_MATHJAX is set to YES.
1537 1805
@@ -1559,7 +1827,7 @@ MATHJAX_CODEFILE =
1559SEARCHENGINE = NO 1827SEARCHENGINE = NO
1560 1828
1561# When the SERVER_BASED_SEARCH tag is enabled the search engine will be 1829# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
1562# implemented using a web server instead of a web client using Javascript. There 1830# implemented using a web server instead of a web client using JavaScript. There
1563# are two flavors of web server based searching depending on the EXTERNAL_SEARCH 1831# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
1564# setting. When disabled, doxygen will generate a PHP script for searching and 1832# setting. When disabled, doxygen will generate a PHP script for searching and
1565# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing 1833# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
@@ -1578,7 +1846,8 @@ SERVER_BASED_SEARCH = NO
1578# 1846#
1579# Doxygen ships with an example indexer (doxyindexer) and search engine 1847# Doxygen ships with an example indexer (doxyindexer) and search engine
1580# (doxysearch.cgi) which are based on the open source search engine library 1848# (doxysearch.cgi) which are based on the open source search engine library
1581# Xapian (see: https://xapian.org/). 1849# Xapian (see:
1850# https://xapian.org/).
1582# 1851#
1583# See the section "External Indexing and Searching" for details. 1852# See the section "External Indexing and Searching" for details.
1584# The default value is: NO. 1853# The default value is: NO.
@@ -1591,8 +1860,9 @@ EXTERNAL_SEARCH = NO
1591# 1860#
1592# Doxygen ships with an example indexer (doxyindexer) and search engine 1861# Doxygen ships with an example indexer (doxyindexer) and search engine
1593# (doxysearch.cgi) which are based on the open source search engine library 1862# (doxysearch.cgi) which are based on the open source search engine library
1594# Xapian (see: https://xapian.org/). See the section "External Indexing and 1863# Xapian (see:
1595# Searching" for details. 1864# https://xapian.org/). See the section "External Indexing and Searching" for
1865# details.
1596# This tag requires that the tag SEARCHENGINE is set to YES. 1866# This tag requires that the tag SEARCHENGINE is set to YES.
1597 1867
1598SEARCHENGINE_URL = 1868SEARCHENGINE_URL =
@@ -1701,29 +1971,31 @@ PAPER_TYPE = a4
1701 1971
1702EXTRA_PACKAGES = 1972EXTRA_PACKAGES =
1703 1973
1704# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the 1974# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
1705# generated LaTeX document. The header should contain everything until the first 1975# the generated LaTeX document. The header should contain everything until the
1706# chapter. If it is left blank doxygen will generate a standard header. See 1976# first chapter. If it is left blank doxygen will generate a standard header. It
1707# section "Doxygen usage" for information on how to let doxygen write the 1977# is highly recommended to start with a default header using
1708# default header to a separate file. 1978# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
1979# and then modify the file new_header.tex. See also section "Doxygen usage" for
1980# information on how to generate the default header that doxygen normally uses.
1709# 1981#
1710# Note: Only use a user-defined header if you know what you are doing! The 1982# Note: Only use a user-defined header if you know what you are doing!
1711# following commands have a special meaning inside the header: $title, 1983# Note: The header is subject to change so you typically have to regenerate the
1712# $datetime, $date, $doxygenversion, $projectname, $projectnumber, 1984# default header when upgrading to a newer version of doxygen. The following
1713# $projectbrief, $projectlogo. Doxygen will replace $title with the empty 1985# commands have a special meaning inside the header (and footer): For a
1714# string, for the replacement values of the other commands the user is referred 1986# description of the possible markers and block names see the documentation.
1715# to HTML_HEADER.
1716# This tag requires that the tag GENERATE_LATEX is set to YES. 1987# This tag requires that the tag GENERATE_LATEX is set to YES.
1717 1988
1718LATEX_HEADER = 1989LATEX_HEADER =
1719 1990
1720# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the 1991# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
1721# generated LaTeX document. The footer should contain everything after the last 1992# the generated LaTeX document. The footer should contain everything after the
1722# chapter. If it is left blank doxygen will generate a standard footer. See 1993# last chapter. If it is left blank doxygen will generate a standard footer. See
1723# LATEX_HEADER for more information on how to generate a default footer and what 1994# LATEX_HEADER for more information on how to generate a default footer and what
1724# special commands can be used inside the footer. 1995# special commands can be used inside the footer. See also section "Doxygen
1725# 1996# usage" for information on how to generate the default footer that doxygen
1726# Note: Only use a user-defined footer if you know what you are doing! 1997# normally uses. Note: Only use a user-defined footer if you know what you are
1998# doing!
1727# This tag requires that the tag GENERATE_LATEX is set to YES. 1999# This tag requires that the tag GENERATE_LATEX is set to YES.
1728 2000
1729LATEX_FOOTER = 2001LATEX_FOOTER =
@@ -1756,18 +2028,26 @@ LATEX_EXTRA_FILES =
1756 2028
1757PDF_HYPERLINKS = NO 2029PDF_HYPERLINKS = NO
1758 2030
1759# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate 2031# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
1760# the PDF file directly from the LaTeX files. Set this option to YES, to get a 2032# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
1761# higher quality PDF documentation. 2033# files. Set this option to YES, to get a higher quality PDF documentation.
2034#
2035# See also section LATEX_CMD_NAME for selecting the engine.
1762# The default value is: YES. 2036# The default value is: YES.
1763# This tag requires that the tag GENERATE_LATEX is set to YES. 2037# This tag requires that the tag GENERATE_LATEX is set to YES.
1764 2038
1765USE_PDFLATEX = NO 2039USE_PDFLATEX = NO
1766 2040
1767# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode 2041# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
1768# command to the generated LaTeX files. This will instruct LaTeX to keep running 2042# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
1769# if errors occur, instead of asking the user for help. This option is also used 2043# mode nothing is printed on the terminal, errors are scrolled as if <return> is
1770# when generating formulas in HTML. 2044# hit at every error; missing files that TeX tries to input or request from
2045# keyboard input (\read on a not open input stream) cause the job to abort,
2046# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
2047# but there is no possibility of user interaction just like in batch mode,
2048# SCROLL In scroll mode, TeX will stop only for missing files to input or if
2049# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
2050# each error, asking for user intervention.
1771# The default value is: NO. 2051# The default value is: NO.
1772# This tag requires that the tag GENERATE_LATEX is set to YES. 2052# This tag requires that the tag GENERATE_LATEX is set to YES.
1773 2053
@@ -1788,14 +2068,6 @@ LATEX_HIDE_INDICES = NO
1788 2068
1789LATEX_BIB_STYLE = plain 2069LATEX_BIB_STYLE = plain
1790 2070
1791# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
1792# page will contain the date and time when the page was generated. Setting this
1793# to NO can help when comparing the output of multiple runs.
1794# The default value is: NO.
1795# This tag requires that the tag GENERATE_LATEX is set to YES.
1796
1797LATEX_TIMESTAMP = NO
1798
1799# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) 2071# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
1800# path from which the emoji images will be read. If a relative path is entered, 2072# path from which the emoji images will be read. If a relative path is entered,
1801# it will be relative to the LATEX_OUTPUT directory. If left blank the 2073# it will be relative to the LATEX_OUTPUT directory. If left blank the
@@ -1860,6 +2132,14 @@ RTF_STYLESHEET_FILE =
1860 2132
1861RTF_EXTENSIONS_FILE = 2133RTF_EXTENSIONS_FILE =
1862 2134
2135# The RTF_EXTRA_FILES tag can be used to specify one or more extra images or
2136# other source files which should be copied to the RTF_OUTPUT output directory.
2137# Note that the files will be copied as-is; there are no commands or markers
2138# available.
2139# This tag requires that the tag GENERATE_RTF is set to YES.
2140
2141RTF_EXTRA_FILES =
2142
1863#--------------------------------------------------------------------------- 2143#---------------------------------------------------------------------------
1864# Configuration options related to the man page output 2144# Configuration options related to the man page output
1865#--------------------------------------------------------------------------- 2145#---------------------------------------------------------------------------
@@ -1961,7 +2241,7 @@ DOCBOOK_OUTPUT = docbook
1961#--------------------------------------------------------------------------- 2241#---------------------------------------------------------------------------
1962 2242
1963# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an 2243# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
1964# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures 2244# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
1965# the structure of the code including all documentation. Note that this feature 2245# the structure of the code including all documentation. Note that this feature
1966# is still experimental and incomplete at the moment. 2246# is still experimental and incomplete at the moment.
1967# The default value is: NO. 2247# The default value is: NO.
@@ -1969,6 +2249,32 @@ DOCBOOK_OUTPUT = docbook
1969GENERATE_AUTOGEN_DEF = NO 2249GENERATE_AUTOGEN_DEF = NO
1970 2250
1971#--------------------------------------------------------------------------- 2251#---------------------------------------------------------------------------
2252# Configuration options related to Sqlite3 output
2253#---------------------------------------------------------------------------
2254
2255# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3
2256# database with symbols found by doxygen stored in tables.
2257# The default value is: NO.
2258
2259GENERATE_SQLITE3 = NO
2260
2261# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
2262# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
2263# in front of it.
2264# The default directory is: sqlite3.
2265# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
2266
2267SQLITE3_OUTPUT = sqlite3
2268
2269# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db
2270# database file will be recreated with each doxygen run. If set to NO, doxygen
2271# will warn if a database file is already found and not modify it.
2272# The default value is: YES.
2273# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
2274
2275SQLITE3_RECREATE_DB = YES
2276
2277#---------------------------------------------------------------------------
1972# Configuration options related to the Perl module output 2278# Configuration options related to the Perl module output
1973#--------------------------------------------------------------------------- 2279#---------------------------------------------------------------------------
1974 2280
@@ -2042,7 +2348,8 @@ SEARCH_INCLUDES = NO
2042 2348
2043# The INCLUDE_PATH tag can be used to specify one or more directories that 2349# The INCLUDE_PATH tag can be used to specify one or more directories that
2044# contain include files that are not input files but should be processed by the 2350# contain include files that are not input files but should be processed by the
2045# preprocessor. 2351# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
2352# RECURSIVE has no effect here.
2046# This tag requires that the tag SEARCH_INCLUDES is set to YES. 2353# This tag requires that the tag SEARCH_INCLUDES is set to YES.
2047 2354
2048INCLUDE_PATH = 2355INCLUDE_PATH =
@@ -2109,15 +2416,15 @@ TAGFILES =
2109 2416
2110GENERATE_TAGFILE = 2417GENERATE_TAGFILE =
2111 2418
2112# If the ALLEXTERNALS tag is set to YES, all external class will be listed in 2419# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
2113# the class index. If set to NO, only the inherited external classes will be 2420# will be listed in the class and namespace index. If set to NO, only the
2114# listed. 2421# inherited external classes will be listed.
2115# The default value is: NO. 2422# The default value is: NO.
2116 2423
2117ALLEXTERNALS = NO 2424ALLEXTERNALS = NO
2118 2425
2119# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed 2426# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
2120# in the modules index. If set to NO, only the current project's groups will be 2427# in the topic index. If set to NO, only the current project's groups will be
2121# listed. 2428# listed.
2122# The default value is: YES. 2429# The default value is: YES.
2123 2430
@@ -2131,25 +2438,9 @@ EXTERNAL_GROUPS = YES
2131EXTERNAL_PAGES = YES 2438EXTERNAL_PAGES = YES
2132 2439
2133#--------------------------------------------------------------------------- 2440#---------------------------------------------------------------------------
2134# Configuration options related to the dot tool 2441# Configuration options related to diagram generator tools
2135#--------------------------------------------------------------------------- 2442#---------------------------------------------------------------------------
2136 2443
2137# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
2138# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
2139# NO turns the diagrams off. Note that this option also works with HAVE_DOT
2140# disabled, but it is recommended to install and use dot, since it yields more
2141# powerful graphs.
2142# The default value is: YES.
2143
2144CLASS_DIAGRAMS = YES
2145
2146# You can include diagrams made with dia in doxygen documentation. Doxygen will
2147# then run dia to produce the diagram and insert it in the documentation. The
2148# DIA_PATH tag allows you to specify the directory where the dia binary resides.
2149# If left empty dia is assumed to be found in the default search path.
2150
2151DIA_PATH =
2152
2153# If set to YES the inheritance and collaboration graphs will hide inheritance 2444# If set to YES the inheritance and collaboration graphs will hide inheritance
2154# and usage relations if the target is undocumented or is not a class. 2445# and usage relations if the target is undocumented or is not a class.
2155# The default value is: YES. 2446# The default value is: YES.
@@ -2158,7 +2449,7 @@ HIDE_UNDOC_RELATIONS = YES
2158 2449
2159# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 2450# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
2160# available from the path. This tool is part of Graphviz (see: 2451# available from the path. This tool is part of Graphviz (see:
2161# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent 2452# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
2162# Bell Labs. The other options in this section have no effect if this option is 2453# Bell Labs. The other options in this section have no effect if this option is
2163# set to NO 2454# set to NO
2164# The default value is: NO. 2455# The default value is: NO.
@@ -2175,49 +2466,77 @@ HAVE_DOT = NO
2175 2466
2176DOT_NUM_THREADS = 0 2467DOT_NUM_THREADS = 0
2177 2468
2178# When you want a differently looking font in the dot files that doxygen 2469# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
2179# generates you can specify the font name using DOT_FONTNAME. You need to make 2470# subgraphs. When you want a differently looking font in the dot files that
2180# sure dot is able to find the font, which can be done by putting it in a 2471# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
2181# standard location or by setting the DOTFONTPATH environment variable or by 2472# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
2182# setting DOT_FONTPATH to the directory containing the font. 2473# Edge and Graph Attributes specification</a> You need to make sure dot is able
2183# The default value is: Helvetica. 2474# to find the font, which can be done by putting it in a standard location or by
2475# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
2476# directory containing the font. Default graphviz fontsize is 14.
2477# The default value is: fontname=Helvetica,fontsize=10.
2184# This tag requires that the tag HAVE_DOT is set to YES. 2478# This tag requires that the tag HAVE_DOT is set to YES.
2185 2479
2186DOT_FONTNAME = 2480DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
2187 2481
2188# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of 2482# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
2189# dot graphs. 2483# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
2190# Minimum value: 4, maximum value: 24, default value: 10. 2484# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
2485# arrows shapes.</a>
2486# The default value is: labelfontname=Helvetica,labelfontsize=10.
2191# This tag requires that the tag HAVE_DOT is set to YES. 2487# This tag requires that the tag HAVE_DOT is set to YES.
2192 2488
2193DOT_FONTSIZE = 10 2489DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
2194 2490
2195# By default doxygen will tell dot to use the default font as specified with 2491# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
2196# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set 2492# around nodes set 'shape=plain' or 'shape=plaintext' <a
2197# the path where dot can find it using this tag. 2493# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
2494# The default value is: shape=box,height=0.2,width=0.4.
2495# This tag requires that the tag HAVE_DOT is set to YES.
2496
2497DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
2498
2499# You can set the path where dot can find font specified with fontname in
2500# DOT_COMMON_ATTR and others dot attributes.
2198# This tag requires that the tag HAVE_DOT is set to YES. 2501# This tag requires that the tag HAVE_DOT is set to YES.
2199 2502
2200DOT_FONTPATH = 2503DOT_FONTPATH =
2201 2504
2202# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for 2505# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
2203# each documented class showing the direct and indirect inheritance relations. 2506# generate a graph for each documented class showing the direct and indirect
2204# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. 2507# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
2508# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
2509# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
2510# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
2511# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
2512# relations will be shown as texts / links. Explicit enabling an inheritance
2513# graph or choosing a different representation for an inheritance graph of a
2514# specific class, can be accomplished by means of the command \inheritancegraph.
2515# Disabling an inheritance graph can be accomplished by means of the command
2516# \hideinheritancegraph.
2517# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
2205# The default value is: YES. 2518# The default value is: YES.
2206# This tag requires that the tag HAVE_DOT is set to YES.
2207 2519
2208CLASS_GRAPH = YES 2520CLASS_GRAPH = YES
2209 2521
2210# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a 2522# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
2211# graph for each documented class showing the direct and indirect implementation 2523# graph for each documented class showing the direct and indirect implementation
2212# dependencies (inheritance, containment, and class references variables) of the 2524# dependencies (inheritance, containment, and class references variables) of the
2213# class with other documented classes. 2525# class with other documented classes. Explicit enabling a collaboration graph,
2526# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
2527# command \collaborationgraph. Disabling a collaboration graph can be
2528# accomplished by means of the command \hidecollaborationgraph.
2214# The default value is: YES. 2529# The default value is: YES.
2215# This tag requires that the tag HAVE_DOT is set to YES. 2530# This tag requires that the tag HAVE_DOT is set to YES.
2216 2531
2217COLLABORATION_GRAPH = YES 2532COLLABORATION_GRAPH = YES
2218 2533
2219# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for 2534# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
2220# groups, showing the direct groups dependencies. 2535# groups, showing the direct groups dependencies. Explicit enabling a group
2536# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
2537# of the command \groupgraph. Disabling a directory graph can be accomplished by
2538# means of the command \hidegroupgraph. See also the chapter Grouping in the
2539# manual.
2221# The default value is: YES. 2540# The default value is: YES.
2222# This tag requires that the tag HAVE_DOT is set to YES. 2541# This tag requires that the tag HAVE_DOT is set to YES.
2223 2542
@@ -2240,10 +2559,32 @@ UML_LOOK = NO
2240# but if the number exceeds 15, the total amount of fields shown is limited to 2559# but if the number exceeds 15, the total amount of fields shown is limited to
2241# 10. 2560# 10.
2242# Minimum value: 0, maximum value: 100, default value: 10. 2561# Minimum value: 0, maximum value: 100, default value: 10.
2243# This tag requires that the tag HAVE_DOT is set to YES. 2562# This tag requires that the tag UML_LOOK is set to YES.
2244 2563
2245UML_LIMIT_NUM_FIELDS = 10 2564UML_LIMIT_NUM_FIELDS = 10
2246 2565
2566# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
2567# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
2568# tag is set to YES, doxygen will add type and arguments for attributes and
2569# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
2570# will not generate fields with class member information in the UML graphs. The
2571# class diagrams will look similar to the default class diagrams but using UML
2572# notation for the relationships.
2573# Possible values are: NO, YES and NONE.
2574# The default value is: NO.
2575# This tag requires that the tag UML_LOOK is set to YES.
2576
2577DOT_UML_DETAILS = NO
2578
2579# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
2580# to display on a single line. If the actual line length exceeds this threshold
2581# significantly it will be wrapped across multiple lines. Some heuristics are
2582# applied to avoid ugly line breaks.
2583# Minimum value: 0, maximum value: 1000, default value: 17.
2584# This tag requires that the tag HAVE_DOT is set to YES.
2585
2586DOT_WRAP_THRESHOLD = 17
2587
2247# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and 2588# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
2248# collaboration graphs will show the relations between templates and their 2589# collaboration graphs will show the relations between templates and their
2249# instances. 2590# instances.
@@ -2255,7 +2596,9 @@ TEMPLATE_RELATIONS = NO
2255# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to 2596# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
2256# YES then doxygen will generate a graph for each documented file showing the 2597# YES then doxygen will generate a graph for each documented file showing the
2257# direct and indirect include dependencies of the file with other documented 2598# direct and indirect include dependencies of the file with other documented
2258# files. 2599# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
2600# can be accomplished by means of the command \includegraph. Disabling an
2601# include graph can be accomplished by means of the command \hideincludegraph.
2259# The default value is: YES. 2602# The default value is: YES.
2260# This tag requires that the tag HAVE_DOT is set to YES. 2603# This tag requires that the tag HAVE_DOT is set to YES.
2261 2604
@@ -2264,7 +2607,10 @@ INCLUDE_GRAPH = YES
2264# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are 2607# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
2265# set to YES then doxygen will generate a graph for each documented file showing 2608# set to YES then doxygen will generate a graph for each documented file showing
2266# the direct and indirect include dependencies of the file with other documented 2609# the direct and indirect include dependencies of the file with other documented
2267# files. 2610# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
2611# to NO, can be accomplished by means of the command \includedbygraph. Disabling
2612# an included by graph can be accomplished by means of the command
2613# \hideincludedbygraph.
2268# The default value is: YES. 2614# The default value is: YES.
2269# This tag requires that the tag HAVE_DOT is set to YES. 2615# This tag requires that the tag HAVE_DOT is set to YES.
2270 2616
@@ -2304,16 +2650,26 @@ GRAPHICAL_HIERARCHY = YES
2304# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the 2650# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
2305# dependencies a directory has on other directories in a graphical way. The 2651# dependencies a directory has on other directories in a graphical way. The
2306# dependency relations are determined by the #include relations between the 2652# dependency relations are determined by the #include relations between the
2307# files in the directories. 2653# files in the directories. Explicit enabling a directory graph, when
2654# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
2655# \directorygraph. Disabling a directory graph can be accomplished by means of
2656# the command \hidedirectorygraph.
2308# The default value is: YES. 2657# The default value is: YES.
2309# This tag requires that the tag HAVE_DOT is set to YES. 2658# This tag requires that the tag HAVE_DOT is set to YES.
2310 2659
2311DIRECTORY_GRAPH = YES 2660DIRECTORY_GRAPH = YES
2312 2661
2662# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
2663# of child directories generated in directory dependency graphs by dot.
2664# Minimum value: 1, maximum value: 25, default value: 1.
2665# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
2666
2667DIR_GRAPH_MAX_DEPTH = 1
2668
2313# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 2669# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
2314# generated by dot. For an explanation of the image formats see the section 2670# generated by dot. For an explanation of the image formats see the section
2315# output formats in the documentation of the dot tool (Graphviz (see: 2671# output formats in the documentation of the dot tool (Graphviz (see:
2316# http://www.graphviz.org/)). 2672# https://www.graphviz.org/)).
2317# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order 2673# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
2318# to make the SVG files visible in IE 9+ (other browsers do not have this 2674# to make the SVG files visible in IE 9+ (other browsers do not have this
2319# requirement). 2675# requirement).
@@ -2350,11 +2706,12 @@ DOT_PATH =
2350 2706
2351DOTFILE_DIRS = 2707DOTFILE_DIRS =
2352 2708
2353# The MSCFILE_DIRS tag can be used to specify one or more directories that 2709# You can include diagrams made with dia in doxygen documentation. Doxygen will
2354# contain msc files that are included in the documentation (see the \mscfile 2710# then run dia to produce the diagram and insert it in the documentation. The
2355# command). 2711# DIA_PATH tag allows you to specify the directory where the dia binary resides.
2712# If left empty dia is assumed to be found in the default search path.
2356 2713
2357MSCFILE_DIRS = 2714DIA_PATH =
2358 2715
2359# The DIAFILE_DIRS tag can be used to specify one or more directories that 2716# The DIAFILE_DIRS tag can be used to specify one or more directories that
2360# contain dia files that are included in the documentation (see the \diafile 2717# contain dia files that are included in the documentation (see the \diafile
@@ -2363,10 +2720,10 @@ MSCFILE_DIRS =
2363DIAFILE_DIRS = 2720DIAFILE_DIRS =
2364 2721
2365# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the 2722# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
2366# path where java can find the plantuml.jar file. If left blank, it is assumed 2723# path where java can find the plantuml.jar file or to the filename of jar file
2367# PlantUML is not used or called during a preprocessing step. Doxygen will 2724# to be used. If left blank, it is assumed PlantUML is not used or called during
2368# generate a warning when it encounters a \startuml command in this case and 2725# a preprocessing step. Doxygen will generate a warning when it encounters a
2369# will not generate output for the diagram. 2726# \startuml command in this case and will not generate output for the diagram.
2370 2727
2371PLANTUML_JAR_PATH = 2728PLANTUML_JAR_PATH =
2372 2729
@@ -2383,7 +2740,7 @@ PLANTUML_INCLUDE_PATH =
2383# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes 2740# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
2384# that will be shown in the graph. If the number of nodes in a graph becomes 2741# that will be shown in the graph. If the number of nodes in a graph becomes
2385# larger than this value, doxygen will truncate the graph, which is visualized 2742# larger than this value, doxygen will truncate the graph, which is visualized
2386# by representing a node as a red box. Note that doxygen if the number of direct 2743# by representing a node as a red box. Note that if the number of direct
2387# children of the root node in a graph is already larger than 2744# children of the root node in a graph is already larger than
2388# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that 2745# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
2389# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. 2746# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
@@ -2404,18 +2761,6 @@ DOT_GRAPH_MAX_NODES = 50
2404 2761
2405MAX_DOT_GRAPH_DEPTH = 0 2762MAX_DOT_GRAPH_DEPTH = 0
2406 2763
2407# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
2408# background. This is disabled by default, because dot on Windows does not seem
2409# to support this out of the box.
2410#
2411# Warning: Depending on the platform used, enabling this option may lead to
2412# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
2413# read).
2414# The default value is: NO.
2415# This tag requires that the tag HAVE_DOT is set to YES.
2416
2417DOT_TRANSPARENT = NO
2418
2419# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output 2764# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
2420# files in one run (i.e. multiple -o and -T options on the command line). This 2765# files in one run (i.e. multiple -o and -T options on the command line). This
2421# makes dot run faster, but since only newer versions of dot (>1.8.10) support 2766# makes dot run faster, but since only newer versions of dot (>1.8.10) support
@@ -2428,14 +2773,34 @@ DOT_MULTI_TARGETS = NO
2428# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page 2773# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
2429# explaining the meaning of the various boxes and arrows in the dot generated 2774# explaining the meaning of the various boxes and arrows in the dot generated
2430# graphs. 2775# graphs.
2776# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
2777# graphical representation for inheritance and collaboration diagrams is used.
2431# The default value is: YES. 2778# The default value is: YES.
2432# This tag requires that the tag HAVE_DOT is set to YES. 2779# This tag requires that the tag HAVE_DOT is set to YES.
2433 2780
2434GENERATE_LEGEND = YES 2781GENERATE_LEGEND = YES
2435 2782
2436# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot 2783# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
2437# files that are used to generate the various graphs. 2784# files that are used to generate the various graphs.
2785#
2786# Note: This setting is not only used for dot files but also for msc temporary
2787# files.
2438# The default value is: YES. 2788# The default value is: YES.
2439# This tag requires that the tag HAVE_DOT is set to YES.
2440 2789
2441DOT_CLEANUP = YES 2790DOT_CLEANUP = YES
2791
2792# You can define message sequence charts within doxygen comments using the \msc
2793# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
2794# use a built-in version of mscgen tool to produce the charts. Alternatively,
2795# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
2796# specifying prog as the value, doxygen will call the tool as prog -T
2797# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
2798# output file formats "png", "eps", "svg", and "ismap".
2799
2800MSCGEN_TOOL =
2801
2802# The MSCFILE_DIRS tag can be used to specify one or more directories that
2803# contain msc files that are included in the documentation (see the \mscfile
2804# command).
2805
2806MSCFILE_DIRS =
diff --git a/include/Makefile.am b/include/Makefile.am
index 2abaf49..a41f53d 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -23,9 +23,11 @@ nobase_include_HEADERS = \
23 libimobiledevice/diagnostics_relay.h \ 23 libimobiledevice/diagnostics_relay.h \
24 libimobiledevice/debugserver.h \ 24 libimobiledevice/debugserver.h \
25 libimobiledevice/syslog_relay.h \ 25 libimobiledevice/syslog_relay.h \
26 libimobiledevice/ostrace.h \
26 libimobiledevice/mobileactivation.h \ 27 libimobiledevice/mobileactivation.h \
27 libimobiledevice/preboard.h \ 28 libimobiledevice/preboard.h \
28 libimobiledevice/companion_proxy.h \ 29 libimobiledevice/companion_proxy.h \
29 libimobiledevice/reverse_proxy.h \ 30 libimobiledevice/reverse_proxy.h \
31 libimobiledevice/bt_packet_logger.h \
30 libimobiledevice/property_list_service.h \ 32 libimobiledevice/property_list_service.h \
31 libimobiledevice/service.h 33 libimobiledevice/service.h
diff --git a/include/endianness.h b/include/endianness.h
index 88b63db..972e51b 100644
--- a/include/endianness.h
+++ b/include/endianness.h
@@ -19,6 +19,13 @@
19#endif 19#endif
20#endif 20#endif
21 21
22#ifndef __BYTE_ORDER
23#ifndef _WIN32
24#warning __BYTE_ORDER is not defined, assuming little endian
25#endif
26#define __BYTE_ORDER __LITTLE_ENDIAN
27#endif
28
22#ifndef be16toh 29#ifndef be16toh
23#if __BYTE_ORDER == __BIG_ENDIAN 30#if __BYTE_ORDER == __BIG_ENDIAN
24#define be16toh(x) (x) 31#define be16toh(x) (x)
diff --git a/include/libimobiledevice/afc.h b/include/libimobiledevice/afc.h
index 4ad3dbd..6e404c3 100644
--- a/include/libimobiledevice/afc.h
+++ b/include/libimobiledevice/afc.h
@@ -64,6 +64,7 @@ typedef enum {
64 AFC_E_NO_MEM = 31, 64 AFC_E_NO_MEM = 31,
65 AFC_E_NOT_ENOUGH_DATA = 32, 65 AFC_E_NOT_ENOUGH_DATA = 32,
66 AFC_E_DIR_NOT_EMPTY = 33, 66 AFC_E_DIR_NOT_EMPTY = 33,
67 AFC_E_SSL_ERROR = 34,
67 AFC_E_FORCE_SIGNED_TYPE = -1 68 AFC_E_FORCE_SIGNED_TYPE = -1
68} afc_error_t; 69} afc_error_t;
69 70
@@ -145,6 +146,20 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_free(afc_client_t client);
145LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char ***device_information); 146LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char ***device_information);
146 147
147/** 148/**
149 * Get device information for a connected client. The device information
150 * returned is the device model as well as the free space, the total capacity
151 * and blocksize on the accessed disk partition.
152 *
153 * @param client The client to get device info for.
154 * @param device_information A pointer to a plist_t that will be populated
155 * with key-value pairs (dictionary) representing the device’s
156 * storage and model information. Free with plist_free().
157 *
158 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
159 */
160LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information);
161
162/**
148 * Gets a directory listing of the directory requested. 163 * Gets a directory listing of the directory requested.
149 * 164 *
150 * @param client The client to get a directory listing from. 165 * @param client The client to get a directory listing from.
@@ -163,7 +178,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const c
163 * @param client The client to use to get the information of the file. 178 * @param client The client to use to get the information of the file.
164 * @param path The fully-qualified path to the file. 179 * @param path The fully-qualified path to the file.
165 * @param file_information Pointer to a buffer that will be filled with a 180 * @param file_information Pointer to a buffer that will be filled with a
166 * NULL-terminated list of strings with the file information. Set to NULL 181 * NULL-terminated list of strings with the file attributes. Set to NULL
167 * before calling this function. Free with afc_dictionary_free(). 182 * before calling this function. Free with afc_dictionary_free().
168 * 183 *
169 * @return AFC_E_SUCCESS on success or an AFC_E_* error value. 184 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
@@ -171,6 +186,19 @@ LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const c
171LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information); 186LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information);
172 187
173/** 188/**
189 * Gets information about a specific file.
190 *
191 * @param client The client to use to get the information of the file.
192 * @param path The fully-qualified path to the file.
193 * @param file_information A pointer to a plist_t that will be populated
194 * with key-value pairs (dictionary) representing the file attributes.
195 * Free with plist_free().
196 *
197 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
198 */
199LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information);
200
201/**
174 * Opens a file on the device. 202 * Opens a file on the device.
175 * 203 *
176 * @param client The client to use to open the file. 204 * @param client The client to use to open the file.
diff --git a/include/libimobiledevice/libimobiledevice.h b/include/libimobiledevice/libimobiledevice.h
index a9d270b..bc57778 100644
--- a/include/libimobiledevice/libimobiledevice.h
+++ b/include/libimobiledevice/libimobiledevice.h
@@ -31,10 +31,13 @@ extern "C" {
31#endif 31#endif
32 32
33#include <stdint.h> 33#include <stdint.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <plist/plist.h> 34#include <plist/plist.h>
37 35
36#if defined(_MSC_VER)
37#include <basetsd.h>
38typedef SSIZE_T ssize_t;
39#endif
40
38#ifndef LIBIMOBILEDEVICE_API 41#ifndef LIBIMOBILEDEVICE_API
39 #ifdef LIBIMOBILEDEVICE_STATIC 42 #ifdef LIBIMOBILEDEVICE_STATIC
40 #define LIBIMOBILEDEVICE_API 43 #define LIBIMOBILEDEVICE_API
@@ -401,12 +404,38 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_handle(idevice_t device, uint32
401LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **udid); 404LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **udid);
402 405
403/** 406/**
407 * Returns the device ProductVersion in numerical form, where "X.Y.Z"
408 * will be returned as (X << 16) | (Y << 8) | Z .
409 * Use IDEVICE_DEVICE_VERSION macro for easy version comparison.
410 * @see IDEVICE_DEVICE_VERSION
411 *
412 * @param client Initialized device client
413 *
414 * @return A numerical representation of the X.Y.Z ProductVersion string
415 * or 0 if the version cannot be retrieved.
416 */
417LIBIMOBILEDEVICE_API unsigned int idevice_get_device_version(idevice_t device);
418
419/**
420 * Gets a readable error string for a given idevice error code.
421 *
422 * @param err An idevice error code
423 *
424 * @return A readable error string
425 */
426LIBIMOBILEDEVICE_API const char* idevice_strerror(idevice_error_t err);
427
428/**
404 * Returns a static string of the libimobiledevice version. 429 * Returns a static string of the libimobiledevice version.
405 * 430 *
406 * @return The libimobiledevice version as static ascii string 431 * @return The libimobiledevice version as static ascii string
407 */ 432 */
408LIBIMOBILEDEVICE_API const char* libimobiledevice_version(); 433LIBIMOBILEDEVICE_API const char* libimobiledevice_version();
409 434
435/* macros */
436/** Helper macro to get a numerical representation of a product version tuple */
437#define IDEVICE_DEVICE_VERSION(maj, min, patch) ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF))
438
410#ifdef __cplusplus 439#ifdef __cplusplus
411} 440}
412#endif 441#endif
diff --git a/include/libimobiledevice/ostrace.h b/include/libimobiledevice/ostrace.h
new file mode 100644
index 0000000..f083ba7
--- /dev/null
+++ b/include/libimobiledevice/ostrace.h
@@ -0,0 +1,198 @@
1/**
2 * @file libimobiledevice/ostrace.h
3 * @brief System log and tracing capabilities.
4 * \internal
5 *
6 * Copyright (c) 2020-2025 Nikias Bassen, All Rights Reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#ifndef OSTRACE_H
24#define OSTRACE_H
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30#include <libimobiledevice/libimobiledevice.h>
31#include <libimobiledevice/lockdown.h>
32
33/** Service identifier passed to lockdownd_start_service() to start the os trace relay service */
34#define OSTRACE_SERVICE_NAME "com.apple.os_trace_relay"
35
36/** Error Codes */
37typedef enum {
38 OSTRACE_E_SUCCESS = 0,
39 OSTRACE_E_INVALID_ARG = -1,
40 OSTRACE_E_MUX_ERROR = -2,
41 OSTRACE_E_SSL_ERROR = -3,
42 OSTRACE_E_NOT_ENOUGH_DATA = -4,
43 OSTRACE_E_TIMEOUT = -5,
44 OSTRACE_E_PLIST_ERROR = -6,
45 OSTRACE_E_REQUEST_FAILED = -7,
46 OSTRACE_E_UNKNOWN_ERROR = -256
47} ostrace_error_t;
48
49typedef struct ostrace_client_private ostrace_client_private; /**< \private */
50typedef ostrace_client_private *ostrace_client_t; /**< The client handle. */
51
52#pragma pack(push,1)
53struct ostrace_packet_header_t {
54 uint8_t marker;
55 uint32_t type;
56 uint32_t header_size; // 0x81
57 uint32_t pid;
58 uint64_t procid; // == pid
59 unsigned char procuuid[16]; // procuuid
60 uint16_t procpath_len; // path to process
61 uint64_t aid; // activity id, usually 0
62 uint64_t paid; // (parent?) activity id, usually 0
63 uint64_t time_sec; // tv.tv_sec 64 bit
64 uint32_t time_usec; // tv.usec 32 bit
65 uint8_t unk06;
66 uint8_t level; // Notice=0, Info=0x01, Debug=0x02, Error=0x10, Fault=0x11
67 uint8_t unk07;
68 uint8_t unk08;
69 uint8_t unk09;
70 uint8_t unk10;
71 uint8_t unk11;
72 uint8_t unk12;
73 uint64_t timestamp; // ?
74 uint32_t thread_id;
75 uint32_t unk13; // 0
76 unsigned char imageuuid[16]; // framework/dylib uuid
77 uint16_t imagepath_len; // framework/dylib
78 uint32_t message_len; // actual log message
79 uint32_t offset; // offset for like timestamp or sth
80 uint16_t subsystem_len; // "subsystem"
81 uint16_t unk14;
82 uint16_t category_len; // "category"
83 uint16_t unk15;
84 uint32_t unk16; // 0
85};
86#pragma pack(pop)
87
88/** Receives unparsed ostrace data from the ostrace service */
89typedef void (*ostrace_activity_cb_t)(const void* buf, size_t len, void *user_data);
90
91/** Receives archive data from the ostrace service */
92typedef int (*ostrace_archive_write_cb_t)(const void* buf, size_t len, void *user_data);
93
94/* Interface */
95
96/**
97 * Connects to the os_trace_relay service on the specified device.
98 *
99 * @param device The device to connect to.
100 * @param service The service descriptor returned by lockdownd_start_service.
101 * @param client Pointer that will point to a newly allocated
102 * ostrace_client_t upon successful return. Must be freed using
103 * ostrace_client_free() after use.
104 *
105 * @return OSTRACE_E_SUCCESS on success, OSTRACE_E_INVALID_ARG when
106 * client is NULL, or an OSTRACE_E_* error code otherwise.
107 */
108LIBIMOBILEDEVICE_API ostrace_error_t ostrace_client_new(idevice_t device, lockdownd_service_descriptor_t service, ostrace_client_t * client);
109
110/**
111 * Starts a new os_trace_relay service on the specified device and connects to it.
112 *
113 * @param device The device to connect to.
114 * @param client Pointer that will point to a newly allocated
115 * ostrace_client_t upon successful return. Must be freed using
116 * ostrace_client_free() after use.
117 * @param label The label to use for communication. Usually the program name.
118 * Pass NULL to disable sending the label in requests to lockdownd.
119 *
120 * @return OSTRACE_E_SUCCESS on success, or an OSTRACE_E_* error code otherwise.
121 */
122LIBIMOBILEDEVICE_API ostrace_error_t ostrace_client_start_service(idevice_t device, ostrace_client_t * client, const char* label);
123
124/**
125 * Disconnects a ostrace client from the device and frees up the
126 * ostrace client data.
127 *
128 * @param client The ostrace client to disconnect and free.
129 *
130 * @return OSTRACE_E_SUCCESS on success, OSTRACE_E_INVALID_ARG when
131 * client is NULL, or an OSTRACE_E_* error code otherwise.
132 */
133LIBIMOBILEDEVICE_API ostrace_error_t ostrace_client_free(ostrace_client_t client);
134
135/**
136 * Starts capturing OS trace activity data of the device using a callback.
137 *
138 * Use ostrace_stop_activity() to stop receiving the ostrace.
139 *
140 * @param client The ostrace client to use
141 * @param options Options dictionary to pass to StartActivity request.
142 * Valid options are MessageFilter (PLIST_INT, default 65535),
143 * Pid (PLIST_INT, default -1), and StreamFlags (PLIST_INT, default 60)
144 * @param callback Callback to receive data from ostrace.
145 * @param user_data Custom pointer passed to the callback function.
146 * @param user_data_free_func Function pointer that will be called when the
147 * activity is stopped to release user_data. Can be NULL for none.
148 *
149 * @return OSTRACE_E_SUCCESS on success,
150 * OSTRACE_E_INVALID_ARG when one or more parameters are
151 * invalid or OSTRACE_E_UNKNOWN_ERROR when an unspecified
152 * error occurs or an ostrace activity has already been started.
153 */
154LIBIMOBILEDEVICE_API ostrace_error_t ostrace_start_activity(ostrace_client_t client, plist_t options, ostrace_activity_cb_t callback, void* user_data);
155
156/**
157 * Stops the ostrace activity.
158 *
159 * Use ostrace_start_activity() to start receiving OS trace data.
160 *
161 * @param client The ostrace client to use
162 *
163 * @return OSTRACE_E_SUCCESS on success,
164 * OSTRACE_E_INVALID_ARG when one or more parameters are
165 * invalid or OSTRACE_E_UNKNOWN_ERROR when an unspecified
166 * error occurs or an ostrace activity has already been started.
167 */
168LIBIMOBILEDEVICE_API ostrace_error_t ostrace_stop_activity(ostrace_client_t client);
169
170/**
171 * Returns a dictionary with all currently running processes on the device.
172 *
173 * @param client The ostrace client to use
174 * @param list Pointer that will receive an allocated PLIST_DICT structure with the process data
175 *
176 * @return OSTRACE_E_SUCCESS on success, or an OSTRACE_E_* error code otherwise
177 */
178LIBIMOBILEDEVICE_API ostrace_error_t ostrace_get_pid_list(ostrace_client_t client, plist_t* list);
179
180/**
181 * Creates a syslog archive.
182 *
183 * @note The device will close the connection once the transfer is complete. The client
184 * is not usable after that anymore and must be disposed with ostrace_client_free.
185 *
186 * @param client The ostrace client to use
187 * @param options A dictionary with options for the request.
188 * Valid parameters are StartTime (PLIST_UINT), SizeLimit (PLIST_UINT), and AgeLimit (PLIST_UINT).
189 *
190 * @return OSTRACE_E_SUCCESS on success, or an OSTRACE_E_* error code otherwise
191 */
192LIBIMOBILEDEVICE_API ostrace_error_t ostrace_create_archive(ostrace_client_t client, plist_t options, ostrace_archive_write_cb_t callback, void* user_data);
193
194#ifdef __cplusplus
195}
196#endif
197
198#endif
diff --git a/m4/ax_python_devel.m4 b/m4/ax_python_devel.m4
index 44dbd83..935056c 100644
--- a/m4/ax_python_devel.m4
+++ b/m4/ax_python_devel.m4
@@ -4,7 +4,7 @@
4# 4#
5# SYNOPSIS 5# SYNOPSIS
6# 6#
7# AX_PYTHON_DEVEL([version]) 7# AX_PYTHON_DEVEL([version[,optional]])
8# 8#
9# DESCRIPTION 9# DESCRIPTION
10# 10#
@@ -23,6 +23,11 @@
23# version number. Don't use "PYTHON_VERSION" for this: that environment 23# version number. Don't use "PYTHON_VERSION" for this: that environment
24# variable is declared as precious and thus reserved for the end-user. 24# variable is declared as precious and thus reserved for the end-user.
25# 25#
26# By default this will fail if it does not detect a development version of
27# python. If you want it to continue, set optional to true, like
28# AX_PYTHON_DEVEL([], [true]). The ax_python_devel_found variable will be
29# "no" if it fails.
30#
26# This macro should work for all versions of Python >= 2.1.0. As an end 31# This macro should work for all versions of Python >= 2.1.0. As an end
27# user, you can disable the check for the python version by setting the 32# user, you can disable the check for the python version by setting the
28# PYTHON_NOVERSIONCHECK environment variable to something else than the 33# PYTHON_NOVERSIONCHECK environment variable to something else than the
@@ -67,10 +72,18 @@
67# modified version of the Autoconf Macro, you may extend this special 72# modified version of the Autoconf Macro, you may extend this special
68# exception to the GPL to apply to your modified version as well. 73# exception to the GPL to apply to your modified version as well.
69 74
70#serial 21 75#serial 37
71 76
72AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL]) 77AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
73AC_DEFUN([AX_PYTHON_DEVEL],[ 78AC_DEFUN([AX_PYTHON_DEVEL],[
79 # Get whether it's optional
80 if test -z "$2"; then
81 ax_python_devel_optional=false
82 else
83 ax_python_devel_optional=$2
84 fi
85 ax_python_devel_found=yes
86
74 # 87 #
75 # Allow the use of a (user set) custom python version 88 # Allow the use of a (user set) custom python version
76 # 89 #
@@ -81,21 +94,26 @@ AC_DEFUN([AX_PYTHON_DEVEL],[
81 94
82 AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]]) 95 AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
83 if test -z "$PYTHON"; then 96 if test -z "$PYTHON"; then
84 AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path]) 97 AC_MSG_WARN([Cannot find python$PYTHON_VERSION in your system path])
98 if ! $ax_python_devel_optional; then
99 AC_MSG_ERROR([Giving up, python development not available])
100 fi
101 ax_python_devel_found=no
85 PYTHON_VERSION="" 102 PYTHON_VERSION=""
86 fi 103 fi
87 104
88 # 105 if test $ax_python_devel_found = yes; then
89 # Check for a version of Python >= 2.1.0 106 #
90 # 107 # Check for a version of Python >= 2.1.0
91 AC_MSG_CHECKING([for a version of Python >= '2.1.0']) 108 #
92 ac_supports_python_ver=`$PYTHON -c "import sys; \ 109 AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
110 ac_supports_python_ver=`$PYTHON -c "import sys; \
93 ver = sys.version.split ()[[0]]; \ 111 ver = sys.version.split ()[[0]]; \
94 print (ver >= '2.1.0')"` 112 print (ver >= '2.1.0')"`
95 if test "$ac_supports_python_ver" != "True"; then 113 if test "$ac_supports_python_ver" != "True"; then
96 if test -z "$PYTHON_NOVERSIONCHECK"; then 114 if test -z "$PYTHON_NOVERSIONCHECK"; then
97 AC_MSG_RESULT([no]) 115 AC_MSG_RESULT([no])
98 AC_MSG_FAILURE([ 116 AC_MSG_WARN([
99This version of the AC@&t@_PYTHON_DEVEL macro 117This version of the AC@&t@_PYTHON_DEVEL macro
100doesn't work properly with versions of Python before 118doesn't work properly with versions of Python before
1012.1.0. You may need to re-run configure, setting the 1192.1.0. You may need to re-run configure, setting the
@@ -104,58 +122,119 @@ PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
104Moreover, to disable this check, set PYTHON_NOVERSIONCHECK 122Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
105to something else than an empty string. 123to something else than an empty string.
106]) 124])
125 if ! $ax_python_devel_optional; then
126 AC_MSG_FAILURE([Giving up])
127 fi
128 ax_python_devel_found=no
129 PYTHON_VERSION=""
107 else 130 else
108 AC_MSG_RESULT([skip at user request]) 131 AC_MSG_RESULT([skip at user request])
109 fi 132 fi
110 else 133 else
111 AC_MSG_RESULT([yes]) 134 AC_MSG_RESULT([yes])
135 fi
112 fi 136 fi
113 137
114 # 138 if test $ax_python_devel_found = yes; then
115 # if the macro parameter ``version'' is set, honour it 139 #
116 # 140 # If the macro parameter ``version'' is set, honour it.
117 if test -n "$1"; then 141 # A Python shim class, VPy, is used to implement correct version comparisons via
142 # string expressions, since e.g. a naive textual ">= 2.7.3" won't work for
143 # Python 2.7.10 (the ".1" being evaluated as less than ".3").
144 #
145 if test -n "$1"; then
118 AC_MSG_CHECKING([for a version of Python $1]) 146 AC_MSG_CHECKING([for a version of Python $1])
119 ac_supports_python_ver=`$PYTHON -c "import sys; \ 147 cat << EOF > ax_python_devel_vpy.py
120 ver = sys.version.split ()[[0]]; \ 148class VPy:
149 def vtup(self, s):
150 return tuple(map(int, s.strip().replace("rc", ".").split(".")))
151 def __init__(self):
152 import sys
153 self.vpy = tuple(sys.version_info)[[:3]]
154 def __eq__(self, s):
155 return self.vpy == self.vtup(s)
156 def __ne__(self, s):
157 return self.vpy != self.vtup(s)
158 def __lt__(self, s):
159 return self.vpy < self.vtup(s)
160 def __gt__(self, s):
161 return self.vpy > self.vtup(s)
162 def __le__(self, s):
163 return self.vpy <= self.vtup(s)
164 def __ge__(self, s):
165 return self.vpy >= self.vtup(s)
166EOF
167 ac_supports_python_ver=`$PYTHON -c "import ax_python_devel_vpy; \
168 ver = ax_python_devel_vpy.VPy(); \
121 print (ver $1)"` 169 print (ver $1)"`
170 rm -rf ax_python_devel_vpy*.py* __pycache__/ax_python_devel_vpy*.py*
122 if test "$ac_supports_python_ver" = "True"; then 171 if test "$ac_supports_python_ver" = "True"; then
123 AC_MSG_RESULT([yes]) 172 AC_MSG_RESULT([yes])
124 else 173 else
125 AC_MSG_RESULT([no]) 174 AC_MSG_RESULT([no])
126 AC_MSG_ERROR([this package requires Python $1. 175 AC_MSG_WARN([this package requires Python $1.
127If you have it installed, but it isn't the default Python 176If you have it installed, but it isn't the default Python
128interpreter in your system path, please pass the PYTHON_VERSION 177interpreter in your system path, please pass the PYTHON_VERSION
129variable to configure. See ``configure --help'' for reference. 178variable to configure. See ``configure --help'' for reference.
130]) 179])
180 if ! $ax_python_devel_optional; then
181 AC_MSG_ERROR([Giving up])
182 fi
183 ax_python_devel_found=no
131 PYTHON_VERSION="" 184 PYTHON_VERSION=""
132 fi 185 fi
186 fi
133 fi 187 fi
134 188
135 # 189 if test $ax_python_devel_found = yes; then
136 # Check if you have distutils, else fail 190 #
137 # 191 # Check if you have distutils, else fail
138 AC_MSG_CHECKING([for the distutils Python package]) 192 #
139 ac_distutils_result=`$PYTHON -c "import distutils" 2>&1` 193 AC_MSG_CHECKING([for the sysconfig Python package])
140 if test $? -eq 0; then 194 ac_sysconfig_result=`$PYTHON -c "import sysconfig" 2>&1`
195 if test $? -eq 0; then
141 AC_MSG_RESULT([yes]) 196 AC_MSG_RESULT([yes])
142 else 197 IMPORT_SYSCONFIG="import sysconfig"
198 else
143 AC_MSG_RESULT([no]) 199 AC_MSG_RESULT([no])
144 AC_MSG_ERROR([cannot import Python module "distutils". 200
201 AC_MSG_CHECKING([for the distutils Python package])
202 ac_sysconfig_result=`$PYTHON -c "from distutils import sysconfig" 2>&1`
203 if test $? -eq 0; then
204 AC_MSG_RESULT([yes])
205 IMPORT_SYSCONFIG="from distutils import sysconfig"
206 else
207 AC_MSG_WARN([cannot import Python module "distutils".
145Please check your Python installation. The error was: 208Please check your Python installation. The error was:
146$ac_distutils_result]) 209$ac_sysconfig_result])
147 PYTHON_VERSION="" 210 if ! $ax_python_devel_optional; then
211 AC_MSG_ERROR([Giving up])
212 fi
213 ax_python_devel_found=no
214 PYTHON_VERSION=""
215 fi
216 fi
148 fi 217 fi
149 218
150 # 219 if test $ax_python_devel_found = yes; then
151 # Check for Python include path 220 #
152 # 221 # Check for Python include path
153 AC_MSG_CHECKING([for Python include path]) 222 #
154 if test -z "$PYTHON_CPPFLAGS"; then 223 AC_MSG_CHECKING([for Python include path])
155 python_path=`$PYTHON -c "import distutils.sysconfig; \ 224 if test -z "$PYTHON_CPPFLAGS"; then
156 print (distutils.sysconfig.get_python_inc ());"` 225 if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
157 plat_python_path=`$PYTHON -c "import distutils.sysconfig; \ 226 # sysconfig module has different functions
158 print (distutils.sysconfig.get_python_inc (plat_specific=1));"` 227 python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
228 print (sysconfig.get_path ('include'));"`
229 plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
230 print (sysconfig.get_path ('platinclude'));"`
231 else
232 # old distutils way
233 python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
234 print (sysconfig.get_python_inc ());"`
235 plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
236 print (sysconfig.get_python_inc (plat_specific=1));"`
237 fi
159 if test -n "${python_path}"; then 238 if test -n "${python_path}"; then
160 if test "${plat_python_path}" != "${python_path}"; then 239 if test "${plat_python_path}" != "${python_path}"; then
161 python_path="-I$python_path -I$plat_python_path" 240 python_path="-I$python_path -I$plat_python_path"
@@ -164,22 +243,22 @@ $ac_distutils_result])
164 fi 243 fi
165 fi 244 fi
166 PYTHON_CPPFLAGS=$python_path 245 PYTHON_CPPFLAGS=$python_path
167 fi 246 fi
168 AC_MSG_RESULT([$PYTHON_CPPFLAGS]) 247 AC_MSG_RESULT([$PYTHON_CPPFLAGS])
169 AC_SUBST([PYTHON_CPPFLAGS]) 248 AC_SUBST([PYTHON_CPPFLAGS])
170 249
171 # 250 #
172 # Check for Python library path 251 # Check for Python library path
173 # 252 #
174 AC_MSG_CHECKING([for Python library path]) 253 AC_MSG_CHECKING([for Python library path])
175 if test -z "$PYTHON_LIBS"; then 254 if test -z "$PYTHON_LIBS"; then
176 # (makes two attempts to ensure we've got a version number 255 # (makes two attempts to ensure we've got a version number
177 # from the interpreter) 256 # from the interpreter)
178 ac_python_version=`cat<<EOD | $PYTHON - 257 ac_python_version=`cat<<EOD | $PYTHON -
179 258
180# join all versioning strings, on some systems 259# join all versioning strings, on some systems
181# major/minor numbers could be in different list elements 260# major/minor numbers could be in different list elements
182from distutils.sysconfig import * 261from sysconfig import *
183e = get_config_var('VERSION') 262e = get_config_var('VERSION')
184if e is not None: 263if e is not None:
185 print(e) 264 print(e)
@@ -190,7 +269,7 @@ EOD`
190 ac_python_version=$PYTHON_VERSION 269 ac_python_version=$PYTHON_VERSION
191 else 270 else
192 ac_python_version=`$PYTHON -c "import sys; \ 271 ac_python_version=`$PYTHON -c "import sys; \
193 print (sys.version[[:3]])"` 272 print ("%d.%d" % sys.version_info[[:2]])"`
194 fi 273 fi
195 fi 274 fi
196 275
@@ -202,8 +281,8 @@ EOD`
202 ac_python_libdir=`cat<<EOD | $PYTHON - 281 ac_python_libdir=`cat<<EOD | $PYTHON -
203 282
204# There should be only one 283# There should be only one
205import distutils.sysconfig 284$IMPORT_SYSCONFIG
206e = distutils.sysconfig.get_config_var('LIBDIR') 285e = sysconfig.get_config_var('LIBDIR')
207if e is not None: 286if e is not None:
208 print (e) 287 print (e)
209EOD` 288EOD`
@@ -211,8 +290,8 @@ EOD`
211 # Now, for the library: 290 # Now, for the library:
212 ac_python_library=`cat<<EOD | $PYTHON - 291 ac_python_library=`cat<<EOD | $PYTHON -
213 292
214import distutils.sysconfig 293$IMPORT_SYSCONFIG
215c = distutils.sysconfig.get_config_vars() 294c = sysconfig.get_config_vars()
216if 'LDVERSION' in c: 295if 'LDVERSION' in c:
217 print ('python'+c[['LDVERSION']]) 296 print ('python'+c[['LDVERSION']])
218else: 297else:
@@ -231,83 +310,140 @@ EOD`
231 else 310 else
232 # old way: use libpython from python_configdir 311 # old way: use libpython from python_configdir
233 ac_python_libdir=`$PYTHON -c \ 312 ac_python_libdir=`$PYTHON -c \
234 "from distutils.sysconfig import get_python_lib as f; \ 313 "from sysconfig import get_python_lib as f; \
235 import os; \ 314 import os; \
236 print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"` 315 print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
237 PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version" 316 PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version"
238 fi 317 fi
239 318
240 if test -z "PYTHON_LIBS"; then 319 if test -z "$PYTHON_LIBS"; then
241 AC_MSG_ERROR([ 320 AC_MSG_WARN([
242 Cannot determine location of your Python DSO. Please check it was installed with 321 Cannot determine location of your Python DSO. Please check it was installed with
243 dynamic libraries enabled, or try setting PYTHON_LIBS by hand. 322 dynamic libraries enabled, or try setting PYTHON_LIBS by hand.
244 ]) 323 ])
324 if ! $ax_python_devel_optional; then
325 AC_MSG_ERROR([Giving up])
326 fi
327 ax_python_devel_found=no
328 PYTHON_VERSION=""
245 fi 329 fi
330 fi
246 fi 331 fi
247 AC_MSG_RESULT([$PYTHON_LIBS])
248 AC_SUBST([PYTHON_LIBS])
249 332
250 # 333 if test $ax_python_devel_found = yes; then
251 # Check for site packages 334 AC_MSG_RESULT([$PYTHON_LIBS])
252 # 335 AC_SUBST([PYTHON_LIBS])
253 AC_MSG_CHECKING([for Python site-packages path])
254 if test -z "$PYTHON_SITE_PKG"; then
255 PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \
256 print (distutils.sysconfig.get_python_lib(0,0));"`
257 fi
258 AC_MSG_RESULT([$PYTHON_SITE_PKG])
259 AC_SUBST([PYTHON_SITE_PKG])
260 336
261 # 337 #
262 # libraries which must be linked in when embedding 338 # Check for site packages
263 # 339 #
264 AC_MSG_CHECKING(python extra libraries) 340 AC_MSG_CHECKING([for Python site-packages path])
265 if test -z "$PYTHON_EXTRA_LIBS"; then 341 if test -z "$PYTHON_SITE_PKG"; then
266 PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \ 342 if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
267 conf = distutils.sysconfig.get_config_var; \ 343 PYTHON_SITE_PKG=`$PYTHON -c "
344$IMPORT_SYSCONFIG;
345if hasattr(sysconfig, 'get_default_scheme'):
346 scheme = sysconfig.get_default_scheme()
347else:
348 scheme = sysconfig._get_default_scheme()
349if scheme == 'posix_local':
350 # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
351 scheme = 'posix_prefix'
352prefix = '$prefix'
353if prefix == 'NONE':
354 prefix = '$ac_default_prefix'
355sitedir = sysconfig.get_path('purelib', scheme, vars={'base': prefix})
356print(sitedir)"`
357 else
358 # distutils.sysconfig way
359 PYTHON_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
360 print (sysconfig.get_python_lib(0,0));"`
361 fi
362 fi
363 AC_MSG_RESULT([$PYTHON_SITE_PKG])
364 AC_SUBST([PYTHON_SITE_PKG])
365
366 #
367 # Check for platform-specific site packages
368 #
369 AC_MSG_CHECKING([for Python platform specific site-packages path])
370 if test -z "$PYTHON_PLATFORM_SITE_PKG"; then
371 if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
372 PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "
373$IMPORT_SYSCONFIG;
374if hasattr(sysconfig, 'get_default_scheme'):
375 scheme = sysconfig.get_default_scheme()
376else:
377 scheme = sysconfig._get_default_scheme()
378if scheme == 'posix_local':
379 # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
380 scheme = 'posix_prefix'
381prefix = '$prefix'
382if prefix == 'NONE':
383 prefix = '$ac_default_prefix'
384sitedir = sysconfig.get_path('platlib', scheme, vars={'platbase': prefix})
385print(sitedir)"`
386 else
387 # distutils.sysconfig way
388 PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
389 print (sysconfig.get_python_lib(1,0));"`
390 fi
391 fi
392 AC_MSG_RESULT([$PYTHON_PLATFORM_SITE_PKG])
393 AC_SUBST([PYTHON_PLATFORM_SITE_PKG])
394
395 #
396 # libraries which must be linked in when embedding
397 #
398 AC_MSG_CHECKING(python extra libraries)
399 if test -z "$PYTHON_EXTRA_LIBS"; then
400 PYTHON_EXTRA_LIBS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
401 conf = sysconfig.get_config_var; \
268 print (conf('LIBS') + ' ' + conf('SYSLIBS'))"` 402 print (conf('LIBS') + ' ' + conf('SYSLIBS'))"`
269 fi 403 fi
270 AC_MSG_RESULT([$PYTHON_EXTRA_LIBS]) 404 AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
271 AC_SUBST(PYTHON_EXTRA_LIBS) 405 AC_SUBST(PYTHON_EXTRA_LIBS)
272 406
273 # 407 #
274 # linking flags needed when embedding 408 # linking flags needed when embedding
275 # 409 #
276 AC_MSG_CHECKING(python extra linking flags) 410 AC_MSG_CHECKING(python extra linking flags)
277 if test -z "$PYTHON_EXTRA_LDFLAGS"; then 411 if test -z "$PYTHON_EXTRA_LDFLAGS"; then
278 PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \ 412 PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
279 conf = distutils.sysconfig.get_config_var; \ 413 conf = sysconfig.get_config_var; \
280 print (conf('LINKFORSHARED'))"` 414 print (conf('LINKFORSHARED'))"`
281 fi 415 # Hack for macos, it sticks this in here.
282 AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS]) 416 PYTHON_EXTRA_LDFLAGS=`echo $PYTHON_EXTRA_LDFLAGS | sed 's/CoreFoundation.*$/CoreFoundation/'`
283 AC_SUBST(PYTHON_EXTRA_LDFLAGS) 417 fi
418 AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
419 AC_SUBST(PYTHON_EXTRA_LDFLAGS)
284 420
285 # 421 #
286 # final check to see if everything compiles alright 422 # final check to see if everything compiles alright
287 # 423 #
288 AC_MSG_CHECKING([consistency of all components of python development environment]) 424 AC_MSG_CHECKING([consistency of all components of python development environment])
289 # save current global flags 425 # save current global flags
290 ac_save_LIBS="$LIBS" 426 ac_save_LIBS="$LIBS"
291 ac_save_LDFLAGS="$LDFLAGS" 427 ac_save_LDFLAGS="$LDFLAGS"
292 ac_save_CPPFLAGS="$CPPFLAGS" 428 ac_save_CPPFLAGS="$CPPFLAGS"
293 LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS $PYTHON_EXTRA_LIBS" 429 LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS"
294 LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS" 430 LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
295 CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS" 431 CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
296 AC_LANG_PUSH([C]) 432 AC_LANG_PUSH([C])
297 AC_LINK_IFELSE([ 433 AC_LINK_IFELSE([
298 AC_LANG_PROGRAM([[#include <Python.h>]], 434 AC_LANG_PROGRAM([[#include <Python.h>]],
299 [[Py_Initialize();]]) 435 [[Py_Initialize();]])
300 ],[pythonexists=yes],[pythonexists=no]) 436 ],[pythonexists=yes],[pythonexists=no])
301 AC_LANG_POP([C]) 437 AC_LANG_POP([C])
302 # turn back to default flags 438 # turn back to default flags
303 CPPFLAGS="$ac_save_CPPFLAGS" 439 CPPFLAGS="$ac_save_CPPFLAGS"
304 LIBS="$ac_save_LIBS" 440 LIBS="$ac_save_LIBS"
305 LDFLAGS="$ac_save_LDFLAGS" 441 LDFLAGS="$ac_save_LDFLAGS"
306 442
307 AC_MSG_RESULT([$pythonexists]) 443 AC_MSG_RESULT([$pythonexists])
308 444
309 if test ! "x$pythonexists" = "xyes"; then 445 if test ! "x$pythonexists" = "xyes"; then
310 AC_MSG_FAILURE([ 446 AC_MSG_WARN([
311 Could not link test program to Python. Maybe the main Python library has been 447 Could not link test program to Python. Maybe the main Python library has been
312 installed in some non-standard library path. If so, pass it to configure, 448 installed in some non-standard library path. If so, pass it to configure,
313 via the LIBS environment variable. 449 via the LIBS environment variable.
@@ -317,8 +453,13 @@ EOD`
317 You probably have to install the development version of the Python package 453 You probably have to install the development version of the Python package
318 for your distribution. The exact name of this package varies among them. 454 for your distribution. The exact name of this package varies among them.
319 ============================================================================ 455 ============================================================================
320 ]) 456 ])
321 PYTHON_VERSION="" 457 if ! $ax_python_devel_optional; then
458 AC_MSG_ERROR([Giving up])
459 fi
460 ax_python_devel_found=no
461 PYTHON_VERSION=""
462 fi
322 fi 463 fi
323 464
324 # 465 #
diff --git a/src/Makefile.am b/src/Makefile.am
index 58cf07c..1ee9be8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -58,6 +58,7 @@ libimobiledevice_1_0_la_SOURCES = \
58 companion_proxy.c companion_proxy.h \ 58 companion_proxy.c companion_proxy.h \
59 reverse_proxy.c reverse_proxy.h \ 59 reverse_proxy.c reverse_proxy.h \
60 syslog_relay.c syslog_relay.h \ 60 syslog_relay.c syslog_relay.h \
61 ostrace.c ostrace.h \
61 bt_packet_logger.c bt_packet_logger.h 62 bt_packet_logger.c bt_packet_logger.h
62 63
63if WIN32 64if WIN32
diff --git a/src/afc.c b/src/afc.c
index 1b4070b..e2e5ba1 100644
--- a/src/afc.c
+++ b/src/afc.c
@@ -26,9 +26,12 @@
26#endif 26#endif
27#include <stdio.h> 27#include <stdio.h>
28#include <stdlib.h> 28#include <stdlib.h>
29#include <unistd.h>
30#include <string.h> 29#include <string.h>
31 30
31#ifndef _MSC_VER
32#include <unistd.h>
33#endif
34
32#include "idevice.h" 35#include "idevice.h"
33#include "afc.h" 36#include "afc.h"
34#include "common/debug.h" 37#include "common/debug.h"
@@ -56,6 +59,27 @@ static void afc_unlock(afc_client_t client)
56 mutex_unlock(&client->mutex); 59 mutex_unlock(&client->mutex);
57} 60}
58 61
62static afc_error_t service_to_afc_error(service_error_t err)
63{
64 switch (err) {
65 case SERVICE_E_SUCCESS:
66 return AFC_E_SUCCESS;
67 case SERVICE_E_INVALID_ARG:
68 return AFC_E_INVALID_ARG;
69 case SERVICE_E_MUX_ERROR:
70 return AFC_E_MUX_ERROR;
71 case SERVICE_E_SSL_ERROR:
72 return AFC_E_SSL_ERROR;
73 case SERVICE_E_NOT_ENOUGH_DATA:
74 return AFC_E_NOT_ENOUGH_DATA;
75 case SERVICE_E_TIMEOUT:
76 return AFC_E_OP_TIMEOUT;
77 default:
78 break;
79 }
80 return AFC_E_UNKNOWN_ERROR;
81}
82
59/** 83/**
60 * Makes a connection to the AFC service on the device using the given 84 * Makes a connection to the AFC service on the device using the given
61 * connection. 85 * connection.
@@ -115,7 +139,7 @@ afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t serv
115 139
116afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label) 140afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label)
117{ 141{
118 afc_error_t err = AFC_E_UNKNOWN_ERROR; 142 int32_t err = AFC_E_UNKNOWN_ERROR;
119 service_client_factory_start_service(device, AFC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(afc_client_new), &err); 143 service_client_factory_start_service(device, AFC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(afc_client_new), &err);
120 return err; 144 return err;
121} 145}
@@ -171,11 +195,16 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation,
171 AFCPacket_to_LE(client->afc_packet); 195 AFCPacket_to_LE(client->afc_packet);
172 debug_buffer((char*)client->afc_packet, sizeof(AFCPacket) + data_length); 196 debug_buffer((char*)client->afc_packet, sizeof(AFCPacket) + data_length);
173 sent = 0; 197 sent = 0;
174 service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket) + data_length, &sent); 198 afc_error_t err = service_to_afc_error(service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket) + data_length, &sent));
175 AFCPacket_from_LE(client->afc_packet); 199 AFCPacket_from_LE(client->afc_packet);
200 if (err != AFC_E_SUCCESS) {
201 debug_info("Failed to send packet (sent %i/%i): %s (%d)", sent, sizeof(AFCPacket) + data_length, afc_strerror(err), err);
202 return err;
203 }
176 *bytes_sent += sent; 204 *bytes_sent += sent;
177 if (sent < sizeof(AFCPacket) + data_length) { 205 if (sent < sizeof(AFCPacket) + data_length) {
178 return AFC_E_SUCCESS; 206 debug_info("Failed to send entire packet (sent %i/%i)", sent, sizeof(AFCPacket) + data_length);
207 return AFC_E_NOT_ENOUGH_DATA;
179 } 208 }
180 209
181 sent = 0; 210 sent = 0;
@@ -187,11 +216,16 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation,
187 debug_info("packet payload follows"); 216 debug_info("packet payload follows");
188 debug_buffer(payload, payload_length); 217 debug_buffer(payload, payload_length);
189 } 218 }
190 service_send(client->parent, payload, payload_length, &sent); 219 err = service_to_afc_error(service_send(client->parent, payload, payload_length, &sent));
220 if (err != AFC_E_SUCCESS) {
221 debug_info("Failed to send payload (sent: %i/%i): %s (%d)", sent, payload_length, afc_strerror(err), err);
222 return err;
223 }
191 } 224 }
192 *bytes_sent += sent; 225 *bytes_sent += sent;
193 if (sent < payload_length) { 226 if (sent < payload_length) {
194 return AFC_E_SUCCESS; 227 debug_info("Failed to send entire payload (sent: %i/%i): %s (%d)", sent, payload_length, afc_strerror(err), err);
228 return AFC_E_NOT_ENOUGH_DATA;
195 } 229 }
196 230
197 return AFC_E_SUCCESS; 231 return AFC_E_SUCCESS;
@@ -224,21 +258,28 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
224 } 258 }
225 259
226 /* first, read the AFC header */ 260 /* first, read the AFC header */
227 service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len); 261 afc_error_t err = service_to_afc_error(service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len));
228 AFCPacket_from_LE(&header); 262 if (err != AFC_E_SUCCESS) {
263 debug_info("Failed to receive AFC header: %s (%d)", afc_strerror(err), err);
264 return err;
265 }
229 if (recv_len == 0) { 266 if (recv_len == 0) {
230 debug_info("Just didn't get enough."); 267 debug_info("Just didn't get enough.");
231 return AFC_E_MUX_ERROR; 268 return AFC_E_NOT_ENOUGH_DATA;
232 } 269 }
233 270
234 if (recv_len < sizeof(AFCPacket)) { 271 if (recv_len < sizeof(AFCPacket)) {
235 debug_info("Did not even get the AFCPacket header"); 272 debug_info("Did not even get the AFCPacket header");
236 return AFC_E_MUX_ERROR; 273 return AFC_E_NOT_ENOUGH_DATA;
237 } 274 }
238 275
276 /* make sure endianness is correct */
277 AFCPacket_from_LE(&header);
278
239 /* check if it's a valid AFC header */ 279 /* check if it's a valid AFC header */
240 if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) { 280 if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) {
241 debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!"); 281 debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!");
282 return AFC_E_UNKNOWN_PACKET_TYPE;
242 } 283 }
243 284
244 /* check if it has the correct packet number */ 285 /* check if it has the correct packet number */
@@ -270,16 +311,20 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
270 buf = (char*)malloc(entire_len); 311 buf = (char*)malloc(entire_len);
271 if (this_len > 0) { 312 if (this_len > 0) {
272 recv_len = 0; 313 recv_len = 0;
273 service_receive(client->parent, buf, this_len, &recv_len); 314 err = service_to_afc_error(service_receive(client->parent, buf, this_len, &recv_len));
315 if (err != AFC_E_SUCCESS) {
316 free(buf);
317 debug_info("Failed to receive data: %s (%d)", afc_strerror(err), err);
318 }
274 if (recv_len <= 0) { 319 if (recv_len <= 0) {
275 free(buf); 320 free(buf);
276 debug_info("Did not get packet contents!"); 321 debug_info("Did not get packet contents!");
277 return AFC_E_NOT_ENOUGH_DATA; 322 return (err == AFC_E_SUCCESS) ? AFC_E_NOT_ENOUGH_DATA : err;
278 } 323 }
279 if (recv_len < this_len) { 324 if (recv_len < this_len) {
280 free(buf); 325 free(buf);
281 debug_info("Could not receive this_len=%d bytes", this_len); 326 debug_info("Could not receive this_len=%d bytes", this_len);
282 return AFC_E_NOT_ENOUGH_DATA; 327 return (err == AFC_E_SUCCESS) ? AFC_E_END_OF_DATA : err;
283 } 328 }
284 } 329 }
285 330
@@ -288,7 +333,11 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
288 if (entire_len > this_len) { 333 if (entire_len > this_len) {
289 while (current_count < entire_len) { 334 while (current_count < entire_len) {
290 recv_len = 0; 335 recv_len = 0;
291 service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len); 336 err = service_to_afc_error(service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len));
337 if (err != AFC_E_SUCCESS) {
338 debug_info("Error receiving data: %s (%d)", afc_strerror(err), err);
339 break;
340 }
292 if (recv_len <= 0) { 341 if (recv_len <= 0) {
293 debug_info("Error receiving data (recv returned %d)", recv_len); 342 debug_info("Error receiving data (recv returned %d)", recv_len);
294 break; 343 break;
@@ -296,7 +345,9 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
296 current_count += recv_len; 345 current_count += recv_len;
297 } 346 }
298 if (current_count < entire_len) { 347 if (current_count < entire_len) {
299 debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len); 348 free(buf);
349 debug_info("ERROR: Could not receive entire packet (read %i/%i)", current_count, entire_len);
350 return (err == AFC_E_SUCCESS) ? AFC_E_END_OF_DATA : err;
300 } 351 }
301 } 352 }
302 353
@@ -338,7 +389,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t
338 free(buf); 389 free(buf);
339 390
340 debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1); 391 debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1);
341#ifndef WIN32 392#ifndef _WIN32
342 fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1); 393 fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1);
343#endif 394#endif
344 395
@@ -399,6 +450,50 @@ static char **make_strings_list(char *tokens, uint32_t length)
399 return list; 450 return list;
400} 451}
401 452
453static plist_t *make_dictionary(char *tokens, size_t length)
454{
455 size_t j = 0;
456 plist_t dict = NULL;
457
458 if (!tokens || !length)
459 return NULL;
460
461 dict = plist_new_dict();
462
463 while (j < length) {
464 size_t key_len = strnlen(tokens + j, length - j);
465 if (j + key_len >= length) {
466 plist_free(dict);
467 return NULL;
468 }
469 char* key = tokens + j;
470 j += key_len + 1;
471
472 if (j >= length) {
473 plist_free(dict);
474 return NULL;
475 }
476
477 size_t val_len = strnlen(tokens + j, length - j);
478 if (j + val_len >= length) {
479 plist_free(dict);
480 return NULL;
481 }
482 char* val = tokens + j;
483 j += val_len + 1;
484
485 char* endp = NULL;
486 unsigned long long u64val = strtoull(val, &endp, 10);
487 if (endp && *endp == '\0') {
488 plist_dict_set_item(dict, key, plist_new_uint(u64val));
489 } else {
490 plist_dict_set_item(dict, key, plist_new_string(val));
491 }
492 }
493
494 return dict;
495}
496
402static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len) 497static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len)
403{ 498{
404 if (data_len > client->packet_extra) { 499 if (data_len > client->packet_extra) {
@@ -495,6 +590,40 @@ afc_error_t afc_get_device_info(afc_client_t client, char ***device_information)
495 return ret; 590 return ret;
496} 591}
497 592
593afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information)
594{
595 uint32_t bytes = 0;
596 char *data = NULL;
597 afc_error_t ret = AFC_E_UNKNOWN_ERROR;
598
599 if (!client || !device_information)
600 return AFC_E_INVALID_ARG;
601
602 afc_lock(client);
603
604 /* Send the command */
605 ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes);
606 if (ret != AFC_E_SUCCESS) {
607 afc_unlock(client);
608 return AFC_E_NOT_ENOUGH_DATA;
609 }
610 /* Receive the data */
611 ret = afc_receive_data(client, &data, &bytes);
612 if (ret != AFC_E_SUCCESS) {
613 if (data)
614 free(data);
615 afc_unlock(client);
616 return ret;
617 }
618 /* Parse the data */
619 *device_information = make_dictionary(data, bytes);
620 free(data);
621
622 afc_unlock(client);
623
624 return ret;
625}
626
498afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) 627afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value)
499{ 628{
500 afc_error_t ret = AFC_E_INTERNAL_ERROR; 629 afc_error_t ret = AFC_E_INTERNAL_ERROR;
@@ -644,8 +773,6 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***fil
644 return AFC_E_NO_MEM; 773 return AFC_E_NO_MEM;
645 } 774 }
646 775
647 debug_info("We got %p and %p", client->afc_packet, AFC_PACKET_DATA_PTR);
648
649 /* Send command */ 776 /* Send command */
650 memcpy(AFC_PACKET_DATA_PTR, path, data_len); 777 memcpy(AFC_PACKET_DATA_PTR, path, data_len);
651 ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes); 778 ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
@@ -666,6 +793,44 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***fil
666 return ret; 793 return ret;
667} 794}
668 795
796afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information)
797{
798 char *received = NULL;
799 uint32_t bytes = 0;
800 afc_error_t ret = AFC_E_UNKNOWN_ERROR;
801
802 if (!client || !path || !file_information)
803 return AFC_E_INVALID_ARG;
804
805 afc_lock(client);
806
807 uint32_t data_len = (uint32_t)strlen(path)+1;
808 if (_afc_check_packet_buffer(client, data_len) < 0) {
809 afc_unlock(client);
810 debug_info("Failed to realloc packet buffer");
811 return AFC_E_NO_MEM;
812 }
813
814 /* Send command */
815 memcpy(AFC_PACKET_DATA_PTR, path, data_len);
816 ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
817 if (ret != AFC_E_SUCCESS) {
818 afc_unlock(client);
819 return AFC_E_NOT_ENOUGH_DATA;
820 }
821
822 /* Receive data */
823 ret = afc_receive_data(client, &received, &bytes);
824 if (received) {
825 *file_information = make_dictionary(received, bytes);
826 free(received);
827 }
828
829 afc_unlock(client);
830
831 return ret;
832}
833
669afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) 834afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle)
670{ 835{
671 if (!client || !client->parent || !client->afc_packet) 836 if (!client || !client->parent || !client->afc_packet)
@@ -1182,14 +1347,14 @@ const char* afc_strerror(afc_error_t err)
1182 return "Internal error"; 1347 return "Internal error";
1183 case AFC_E_MUX_ERROR: 1348 case AFC_E_MUX_ERROR:
1184 return "MUX error"; 1349 return "MUX error";
1350 case AFC_E_SSL_ERROR:
1351 return "SSL error";
1185 case AFC_E_NO_MEM: 1352 case AFC_E_NO_MEM:
1186 return "Out of memory"; 1353 return "Out of memory";
1187 case AFC_E_NOT_ENOUGH_DATA: 1354 case AFC_E_NOT_ENOUGH_DATA:
1188 return "Not enough data"; 1355 return "Not enough data";
1189 case AFC_E_DIR_NOT_EMPTY: 1356 case AFC_E_DIR_NOT_EMPTY:
1190 return "Directory not empty"; 1357 return "Directory not empty";
1191 case AFC_E_FORCE_SIGNED_TYPE:
1192 return "Force signed type";
1193 default: 1358 default:
1194 break; 1359 break;
1195 } 1360 }
diff --git a/src/house_arrest.c b/src/house_arrest.c
index caad731..06068c6 100644
--- a/src/house_arrest.c
+++ b/src/house_arrest.c
@@ -24,7 +24,11 @@
24#endif 24#endif
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27
28#ifndef _MSC_VER
27#include <unistd.h> 29#include <unistd.h>
30#endif
31
28#include <plist/plist.h> 32#include <plist/plist.h>
29 33
30#include "house_arrest.h" 34#include "house_arrest.h"
diff --git a/src/idevice.c b/src/idevice.c
index b9bbb1f..0af27fd 100644
--- a/src/idevice.c
+++ b/src/idevice.c
@@ -30,7 +30,7 @@
30#include <errno.h> 30#include <errno.h>
31#include <time.h> 31#include <time.h>
32 32
33#ifdef WIN32 33#ifdef _WIN32
34#include <winsock2.h> 34#include <winsock2.h>
35#include <ws2tcpip.h> 35#include <ws2tcpip.h>
36#include <windows.h> 36#include <windows.h>
@@ -124,32 +124,32 @@ static void id_function(CRYPTO_THREADID *thread)
124#endif 124#endif
125#endif /* HAVE_OPENSSL */ 125#endif /* HAVE_OPENSSL */
126 126
127static void internal_idevice_init(void) 127// Reference: https://stackoverflow.com/a/2390626/1806760
128{ 128// Initializer/finalizer sample for MSVC and GCC/Clang.
129#if defined(HAVE_OPENSSL) 129// 2010-2016 Joe Lowe. Released into the public domain.
130#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) 130
131 int i; 131#ifdef __cplusplus
132 SSL_library_init(); 132 #define INITIALIZER(f) \
133 133 static void f(void); \
134 mutex_buf = malloc(CRYPTO_num_locks() * sizeof(mutex_t)); 134 struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
135 if (!mutex_buf) 135 static void f(void)
136 return; 136#elif defined(_MSC_VER)
137 for (i = 0; i < CRYPTO_num_locks(); i++) 137 #pragma section(".CRT$XCU",read)
138 mutex_init(&mutex_buf[i]); 138 #define INITIALIZER2_(f,p) \
139 139 static void f(void); \
140#if OPENSSL_VERSION_NUMBER < 0x10000000L 140 __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
141 CRYPTO_set_id_callback(id_function); 141 __pragma(comment(linker,"/include:" p #f "_")) \
142 static void f(void)
143 #ifdef _WIN64
144 #define INITIALIZER(f) INITIALIZER2_(f,"")
145 #else
146 #define INITIALIZER(f) INITIALIZER2_(f,"_")
147 #endif
142#else 148#else
143 CRYPTO_THREADID_set_callback(id_function); 149 #define INITIALIZER(f) \
144#endif 150 static void f(void) __attribute__((__constructor__)); \
145 CRYPTO_set_locking_callback(locking_function); 151 static void f(void)
146#endif
147#elif defined(HAVE_GNUTLS)
148 gnutls_global_init();
149#elif defined(HAVE_MBEDTLS)
150 // NO-OP
151#endif 152#endif
152}
153 153
154static void internal_idevice_deinit(void) 154static void internal_idevice_deinit(void)
155{ 155{
@@ -181,43 +181,33 @@ static void internal_idevice_deinit(void)
181#endif 181#endif
182} 182}
183 183
184static thread_once_t init_once = THREAD_ONCE_INIT; 184INITIALIZER(internal_idevice_init)
185static thread_once_t deinit_once = THREAD_ONCE_INIT;
186
187#ifndef HAVE_ATTRIBUTE_CONSTRUCTOR
188 #if defined(__llvm__) || defined(__GNUC__)
189 #define HAVE_ATTRIBUTE_CONSTRUCTOR
190 #endif
191#endif
192
193#ifdef HAVE_ATTRIBUTE_CONSTRUCTOR
194static void __attribute__((constructor)) libimobiledevice_initialize(void)
195{ 185{
196 thread_once(&init_once, internal_idevice_init); 186#if defined(HAVE_OPENSSL)
197} 187#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
188 int i;
189 SSL_library_init();
198 190
199static void __attribute__((destructor)) libimobiledevice_deinitialize(void) 191 mutex_buf = malloc(CRYPTO_num_locks() * sizeof(mutex_t));
200{ 192 if (!mutex_buf)
201 thread_once(&deinit_once, internal_idevice_deinit); 193 return;
202} 194 for (i = 0; i < CRYPTO_num_locks(); i++)
203#elif defined(WIN32) 195 mutex_init(&mutex_buf[i]);
204BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) 196
205{ 197#if OPENSSL_VERSION_NUMBER < 0x10000000L
206 switch (dwReason) { 198 CRYPTO_set_id_callback(id_function);
207 case DLL_PROCESS_ATTACH:
208 thread_once(&init_once, internal_idevice_init);
209 break;
210 case DLL_PROCESS_DETACH:
211 thread_once(&deinit_once, internal_idevice_deinit);
212 break;
213 default:
214 break;
215 }
216 return 1;
217}
218#else 199#else
219#warning No compiler support for constructor/destructor attributes, some features might not be available. 200 CRYPTO_THREADID_set_callback(id_function);
201#endif
202 CRYPTO_set_locking_callback(locking_function);
203#endif
204#elif defined(HAVE_GNUTLS)
205 gnutls_global_init();
206#elif defined(HAVE_MBEDTLS)
207 // NO-OP
220#endif 208#endif
209 atexit(internal_idevice_deinit);
210}
221 211
222const char* libimobiledevice_version() 212const char* libimobiledevice_version()
223{ 213{
@@ -548,7 +538,7 @@ idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connect
548 } 538 }
549 idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private)); 539 idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private));
550 new_connection->type = CONNECTION_USBMUXD; 540 new_connection->type = CONNECTION_USBMUXD;
551 new_connection->data = (void*)(long)sfd; 541 new_connection->data = (void*)(uintptr_t)sfd;
552 new_connection->ssl_data = NULL; 542 new_connection->ssl_data = NULL;
553 new_connection->device = device; 543 new_connection->device = device;
554 new_connection->ssl_recv_timeout = (unsigned int)-1; 544 new_connection->ssl_recv_timeout = (unsigned int)-1;
@@ -593,7 +583,7 @@ idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connect
593 583
594 idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private)); 584 idevice_connection_t new_connection = (idevice_connection_t)malloc(sizeof(struct idevice_connection_private));
595 new_connection->type = CONNECTION_NETWORK; 585 new_connection->type = CONNECTION_NETWORK;
596 new_connection->data = (void*)(long)sfd; 586 new_connection->data = (void*)(uintptr_t)sfd;
597 new_connection->ssl_data = NULL; 587 new_connection->ssl_data = NULL;
598 new_connection->device = device; 588 new_connection->device = device;
599 new_connection->ssl_recv_timeout = (unsigned int)-1; 589 new_connection->ssl_recv_timeout = (unsigned int)-1;
@@ -618,11 +608,11 @@ idevice_error_t idevice_disconnect(idevice_connection_t connection)
618 } 608 }
619 idevice_error_t result = IDEVICE_E_UNKNOWN_ERROR; 609 idevice_error_t result = IDEVICE_E_UNKNOWN_ERROR;
620 if (connection->type == CONNECTION_USBMUXD) { 610 if (connection->type == CONNECTION_USBMUXD) {
621 usbmuxd_disconnect((int)(long)connection->data); 611 usbmuxd_disconnect((int)(uintptr_t)connection->data);
622 connection->data = NULL; 612 connection->data = NULL;
623 result = IDEVICE_E_SUCCESS; 613 result = IDEVICE_E_SUCCESS;
624 } else if (connection->type == CONNECTION_NETWORK) { 614 } else if (connection->type == CONNECTION_NETWORK) {
625 socket_close((int)(long)connection->data); 615 socket_close((int)(uintptr_t)connection->data);
626 connection->data = NULL; 616 connection->data = NULL;
627 result = IDEVICE_E_SUCCESS; 617 result = IDEVICE_E_SUCCESS;
628 } else { 618 } else {
@@ -647,7 +637,7 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection,
647 if (connection->type == CONNECTION_USBMUXD) { 637 if (connection->type == CONNECTION_USBMUXD) {
648 int res; 638 int res;
649 do { 639 do {
650 res = usbmuxd_send((int)(long)connection->data, data, len, sent_bytes); 640 res = usbmuxd_send((int)(uintptr_t)connection->data, data, len, sent_bytes);
651 } while (res == -EAGAIN); 641 } while (res == -EAGAIN);
652 if (res < 0) { 642 if (res < 0) {
653 debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res)); 643 debug_info("ERROR: usbmuxd_send returned %d (%s)", res, strerror(-res));
@@ -656,7 +646,7 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection,
656 return IDEVICE_E_SUCCESS; 646 return IDEVICE_E_SUCCESS;
657 } 647 }
658 if (connection->type == CONNECTION_NETWORK) { 648 if (connection->type == CONNECTION_NETWORK) {
659 int s = socket_send((int)(long)connection->data, (void*)data, len); 649 int s = socket_send((int)(uintptr_t)connection->data, (void*)data, len);
660 if (s < 0) { 650 if (s < 0) {
661 *sent_bytes = 0; 651 *sent_bytes = 0;
662 return IDEVICE_E_UNKNOWN_ERROR; 652 return IDEVICE_E_UNKNOWN_ERROR;
@@ -763,7 +753,7 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t
763 } 753 }
764 754
765 if (connection->type == CONNECTION_USBMUXD) { 755 if (connection->type == CONNECTION_USBMUXD) {
766 int conn_error = usbmuxd_recv_timeout((int)(long)connection->data, data, len, recv_bytes, timeout); 756 int conn_error = usbmuxd_recv_timeout((int)(uintptr_t)connection->data, data, len, recv_bytes, timeout);
767 idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, *recv_bytes); 757 idevice_error_t error = socket_recv_to_idevice_error(conn_error, len, *recv_bytes);
768 if (error == IDEVICE_E_UNKNOWN_ERROR) { 758 if (error == IDEVICE_E_UNKNOWN_ERROR) {
769 debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", conn_error, strerror(-conn_error)); 759 debug_info("ERROR: usbmuxd_recv_timeout returned %d (%s)", conn_error, strerror(-conn_error));
@@ -771,7 +761,7 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t
771 return error; 761 return error;
772 } 762 }
773 if (connection->type == CONNECTION_NETWORK) { 763 if (connection->type == CONNECTION_NETWORK) {
774 int res = socket_receive_timeout((int)(long)connection->data, data, len, 0, timeout); 764 int res = socket_receive_timeout((int)(uintptr_t)connection->data, data, len, 0, timeout);
775 idevice_error_t error = socket_recv_to_idevice_error(res, 0, 0); 765 idevice_error_t error = socket_recv_to_idevice_error(res, 0, 0);
776 if (error == IDEVICE_E_SUCCESS) { 766 if (error == IDEVICE_E_SUCCESS) {
777 *recv_bytes = (uint32_t)res; 767 *recv_bytes = (uint32_t)res;
@@ -863,7 +853,7 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti
863 } 853 }
864 854
865 if (connection->type == CONNECTION_USBMUXD) { 855 if (connection->type == CONNECTION_USBMUXD) {
866 int res = usbmuxd_recv((int)(long)connection->data, data, len, recv_bytes); 856 int res = usbmuxd_recv((int)(uintptr_t)connection->data, data, len, recv_bytes);
867 if (res < 0) { 857 if (res < 0) {
868 debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res)); 858 debug_info("ERROR: usbmuxd_recv returned %d (%s)", res, strerror(-res));
869 return IDEVICE_E_UNKNOWN_ERROR; 859 return IDEVICE_E_UNKNOWN_ERROR;
@@ -871,7 +861,7 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti
871 return IDEVICE_E_SUCCESS; 861 return IDEVICE_E_SUCCESS;
872 } 862 }
873 if (connection->type == CONNECTION_NETWORK) { 863 if (connection->type == CONNECTION_NETWORK) {
874 int res = socket_receive((int)(long)connection->data, data, len); 864 int res = socket_receive((int)(uintptr_t)connection->data, data, len);
875 if (res < 0) { 865 if (res < 0) {
876 debug_info("ERROR: socket_receive returned %d (%s)", res, strerror(-res)); 866 debug_info("ERROR: socket_receive returned %d (%s)", res, strerror(-res));
877 return IDEVICE_E_UNKNOWN_ERROR; 867 return IDEVICE_E_UNKNOWN_ERROR;
@@ -924,11 +914,11 @@ idevice_error_t idevice_connection_get_fd(idevice_connection_t connection, int *
924 } 914 }
925 915
926 if (connection->type == CONNECTION_USBMUXD) { 916 if (connection->type == CONNECTION_USBMUXD) {
927 *fd = (int)(long)connection->data; 917 *fd = (int)(uintptr_t)connection->data;
928 return IDEVICE_E_SUCCESS; 918 return IDEVICE_E_SUCCESS;
929 } 919 }
930 if (connection->type == CONNECTION_NETWORK) { 920 if (connection->type == CONNECTION_NETWORK) {
931 *fd = (int)(long)connection->data; 921 *fd = (int)(uintptr_t)connection->data;
932 return IDEVICE_E_SUCCESS; 922 return IDEVICE_E_SUCCESS;
933 } 923 }
934 924
@@ -956,6 +946,20 @@ idevice_error_t idevice_get_udid(idevice_t device, char **udid)
956 return IDEVICE_E_SUCCESS; 946 return IDEVICE_E_SUCCESS;
957} 947}
958 948
949unsigned int idevice_get_device_version(idevice_t device)
950{
951 if (!device) {
952 return 0;
953 }
954 if (!device->version) {
955 lockdownd_client_t lockdown = NULL;
956 lockdownd_client_new(device, &lockdown, NULL);
957 // we don't handle any errors here. We should have the product version cached now.
958 lockdownd_client_free(lockdown);
959 }
960 return device->version;
961}
962
959#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS) 963#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
960typedef ssize_t ssl_cb_ret_type_t; 964typedef ssize_t ssl_cb_ret_type_t;
961#elif defined(HAVE_MBEDTLS) 965#elif defined(HAVE_MBEDTLS)
@@ -1075,13 +1079,14 @@ static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int arg
1075 idevice_connection_t conn = (idevice_connection_t)BIO_get_callback_arg(b); 1079 idevice_connection_t conn = (idevice_connection_t)BIO_get_callback_arg(b);
1076#if OPENSSL_VERSION_NUMBER < 0x30000000L 1080#if OPENSSL_VERSION_NUMBER < 0x30000000L
1077 size_t len = (size_t)argi; 1081 size_t len = (size_t)argi;
1078 size_t *processed = (size_t*)&bytes;
1079#endif 1082#endif
1080 switch (oper) { 1083 switch (oper) {
1081 case (BIO_CB_READ|BIO_CB_RETURN): 1084 case (BIO_CB_READ|BIO_CB_RETURN):
1082 if (argp) { 1085 if (argp) {
1083 bytes = internal_ssl_read(conn, (char *)argp, len); 1086 bytes = internal_ssl_read(conn, (char *)argp, len);
1084 *processed = bytes; 1087#if OPENSSL_VERSION_NUMBER >= 0x30000000L
1088 *processed = (size_t)(bytes < 0) ? 0 : bytes;
1089#endif
1085 return (long)bytes; 1090 return (long)bytes;
1086 } 1091 }
1087 return 0; 1092 return 0;
@@ -1090,7 +1095,9 @@ static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int arg
1090 // fallthrough 1095 // fallthrough
1091 case (BIO_CB_WRITE|BIO_CB_RETURN): 1096 case (BIO_CB_WRITE|BIO_CB_RETURN):
1092 bytes = internal_ssl_write(conn, argp, len); 1097 bytes = internal_ssl_write(conn, argp, len);
1093 *processed = bytes; 1098#if OPENSSL_VERSION_NUMBER >= 0x30000000L
1099 *processed = (size_t)(bytes < 0) ? 0 : bytes;
1100#endif
1094 return (long)bytes; 1101 return (long)bytes;
1095 default: 1102 default:
1096 return retvalue; 1103 return retvalue;
@@ -1239,7 +1246,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
1239#if OPENSSL_VERSION_NUMBER < 0x10100002L || \ 1246#if OPENSSL_VERSION_NUMBER < 0x10100002L || \
1240 (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2060000fL)) 1247 (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2060000fL))
1241 /* force use of TLSv1 for older devices */ 1248 /* force use of TLSv1 for older devices */
1242 if (connection->device->version < DEVICE_VERSION(10,0,0)) { 1249 if (connection->device->version < IDEVICE_DEVICE_VERSION(10,0,0)) {
1243#ifdef SSL_OP_NO_TLSv1_1 1250#ifdef SSL_OP_NO_TLSv1_1
1244 SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1); 1251 SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
1245#endif 1252#endif
@@ -1252,7 +1259,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
1252 } 1259 }
1253#else 1260#else
1254 SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION); 1261 SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION);
1255 if (connection->device->version < DEVICE_VERSION(10,0,0)) { 1262 if (connection->device->version < IDEVICE_DEVICE_VERSION(10,0,0)) {
1256 SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_VERSION); 1263 SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_VERSION);
1257 if (connection->device->version == 0) { 1264 if (connection->device->version == 0) {
1258 /* 1265 /*
@@ -1338,7 +1345,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
1338 if (ssl_error == 0 || ssl_error != SSL_ERROR_WANT_READ) { 1345 if (ssl_error == 0 || ssl_error != SSL_ERROR_WANT_READ) {
1339 break; 1346 break;
1340 } 1347 }
1341#ifdef WIN32 1348#ifdef _WIN32
1342 Sleep(100); 1349 Sleep(100);
1343#else 1350#else
1344 struct timespec ts = { 0, 100000000 }; 1351 struct timespec ts = { 0, 100000000 };
@@ -1544,3 +1551,28 @@ idevice_error_t idevice_connection_disable_bypass_ssl(idevice_connection_t conne
1544 1551
1545 return IDEVICE_E_SUCCESS; 1552 return IDEVICE_E_SUCCESS;
1546} 1553}
1554
1555const char* idevice_strerror(idevice_error_t err)
1556{
1557 switch (err) {
1558 case IDEVICE_E_SUCCESS:
1559 return "Success";
1560 case IDEVICE_E_INVALID_ARG:
1561 return "Invalid argument";
1562 case IDEVICE_E_UNKNOWN_ERROR:
1563 return "Unknown Error";
1564 case IDEVICE_E_NO_DEVICE:
1565 return "No device";
1566 case IDEVICE_E_NOT_ENOUGH_DATA:
1567 return "Not enough data";
1568 case IDEVICE_E_CONNREFUSED:
1569 return "Connection refused";
1570 case IDEVICE_E_SSL_ERROR:
1571 return "SSL error";
1572 case IDEVICE_E_TIMEOUT:
1573 return "Timeout";
1574 default:
1575 break;
1576 }
1577 return "Unknown Error";
1578}
diff --git a/src/idevice.h b/src/idevice.h
index dd72f9d..e05338e 100644
--- a/src/idevice.h
+++ b/src/idevice.h
@@ -52,8 +52,6 @@
52#include "common/userpref.h" 52#include "common/userpref.h"
53#include "libimobiledevice/libimobiledevice.h" 53#include "libimobiledevice/libimobiledevice.h"
54 54
55#define DEVICE_VERSION(maj, min, patch) (((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (patch & 0xFF))
56
57#define DEVICE_CLASS_IPHONE 1 55#define DEVICE_CLASS_IPHONE 1
58#define DEVICE_CLASS_IPAD 2 56#define DEVICE_CLASS_IPAD 2
59#define DEVICE_CLASS_IPOD 3 57#define DEVICE_CLASS_IPOD 3
diff --git a/src/installation_proxy.c b/src/installation_proxy.c
index ec19da0..bb6ef01 100644
--- a/src/installation_proxy.c
+++ b/src/installation_proxy.c
@@ -26,7 +26,11 @@
26#include <string.h> 26#include <string.h>
27#include <stdlib.h> 27#include <stdlib.h>
28#include <inttypes.h> 28#include <inttypes.h>
29
30#ifndef _MSC_VER
29#include <unistd.h> 31#include <unistd.h>
32#endif
33
30#include <plist/plist.h> 34#include <plist/plist.h>
31 35
32#include "installation_proxy.h" 36#include "installation_proxy.h"
@@ -251,7 +255,7 @@ instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descr
251 255
252instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label) 256instproxy_error_t instproxy_client_start_service(idevice_t device, instproxy_client_t * client, const char* label)
253{ 257{
254 instproxy_error_t err = INSTPROXY_E_UNKNOWN_ERROR; 258 int32_t err = INSTPROXY_E_UNKNOWN_ERROR;
255 service_client_factory_start_service(device, INSTPROXY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(instproxy_client_new), &err); 259 service_client_factory_start_service(device, INSTPROXY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(instproxy_client_new), &err);
256 return err; 260 return err;
257} 261}
diff --git a/src/lockdown-cu.c b/src/lockdown-cu.c
index 1afc2c5..c457cb2 100644
--- a/src/lockdown-cu.c
+++ b/src/lockdown-cu.c
@@ -29,7 +29,11 @@
29#define __USE_GNU 1 29#define __USE_GNU 1
30#include <stdio.h> 30#include <stdio.h>
31#include <ctype.h> 31#include <ctype.h>
32
33#ifndef _MSC_VER
32#include <unistd.h> 34#include <unistd.h>
35#endif
36
33#include <plist/plist.h> 37#include <plist/plist.h>
34 38
35#include "idevice.h" 39#include "idevice.h"
@@ -505,7 +509,7 @@ lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdow
505 char *s_version = NULL; 509 char *s_version = NULL;
506 plist_get_string_val(p_version, &s_version); 510 plist_get_string_val(p_version, &s_version);
507 if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) { 511 if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
508 client->device->version = DEVICE_VERSION(vers[0], vers[1], vers[2]); 512 client->device->version = IDEVICE_DEVICE_VERSION(vers[0], vers[1], vers[2]);
509 } 513 }
510 free(s_version); 514 free(s_version);
511 } 515 }
@@ -653,7 +657,7 @@ lockdownd_error_t lockdownd_cu_pairing_create(lockdownd_client_t client, lockdow
653 CFStringGetCString(cname, hostname, sizeof(hostname), kCFStringEncodingUTF8); 657 CFStringGetCString(cname, hostname, sizeof(hostname), kCFStringEncodingUTF8);
654 CFRelease(cname); 658 CFRelease(cname);
655#else 659#else
656#ifdef WIN32 660#ifdef _WIN32
657 DWORD hostname_len = sizeof(hostname); 661 DWORD hostname_len = sizeof(hostname);
658 GetComputerName(hostname, &hostname_len); 662 GetComputerName(hostname, &hostname_len);
659#else 663#else
@@ -957,12 +961,12 @@ lockdownd_error_t lockdownd_cu_send_request_and_get_reply(lockdownd_client_t cli
957 hkdf_md(MD_ALGO_SHA512, (unsigned char*)READ_KEY_SALT_MDLD, sizeof(READ_KEY_SALT_MDLD)-1, (unsigned char*)READ_KEY_INFO_MDLD, sizeof(READ_KEY_INFO_MDLD)-1, client->cu_key, client->cu_key_len, cu_read_key, &cu_read_key_len); 961 hkdf_md(MD_ALGO_SHA512, (unsigned char*)READ_KEY_SALT_MDLD, sizeof(READ_KEY_SALT_MDLD)-1, (unsigned char*)READ_KEY_INFO_MDLD, sizeof(READ_KEY_INFO_MDLD)-1, client->cu_key, client->cu_key_len, cu_read_key, &cu_read_key_len);
958 962
959 // Starting with iOS/tvOS 11.2 and WatchOS 4.2, this nonce is random and sent along with the request. Before, the request doesn't have a nonce and it uses hardcoded nonce "sendone01234". 963 // Starting with iOS/tvOS 11.2 and WatchOS 4.2, this nonce is random and sent along with the request. Before, the request doesn't have a nonce and it uses hardcoded nonce "sendone01234".
960 unsigned char cu_nonce[12] = "sendone01234"; // guaranteed to be random by fair dice troll 964 unsigned char cu_nonce[] = "sendone01234"; // guaranteed to be random by fair dice troll
961 if (client->device->version >= DEVICE_VERSION(11,2,0)) { 965 if (client->device->version >= IDEVICE_DEVICE_VERSION(11,2,0)) {
962#if defined(HAVE_OPENSSL) 966#if defined(HAVE_OPENSSL)
963 RAND_bytes(cu_nonce, sizeof(cu_nonce)); 967 RAND_bytes(cu_nonce, sizeof(cu_nonce)-1);
964#elif defined(HAVE_GCRYPT) 968#elif defined(HAVE_GCRYPT)
965 gcry_create_nonce(cu_nonce, sizeof(cu_nonce)); 969 gcry_create_nonce(cu_nonce, sizeof(cu_nonce)-1);
966#endif 970#endif
967 } 971 }
968 972
@@ -1128,7 +1132,7 @@ lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client)
1128 plist_free(pubkey); 1132 plist_free(pubkey);
1129 1133
1130 plist_t pair_record_plist = plist_new_dict(); 1134 plist_t pair_record_plist = plist_new_dict();
1131 pair_record_generate_keys_and_certs(pair_record_plist, public_key); 1135 pair_record_generate_keys_and_certs(pair_record_plist, public_key, client->device->version);
1132 1136
1133 char* host_id = NULL; 1137 char* host_id = NULL;
1134 char* system_buid = NULL; 1138 char* system_buid = NULL;
diff --git a/src/lockdown.c b/src/lockdown.c
index 256bff0..32389c9 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -32,7 +32,11 @@
32#define __USE_GNU 1 32#define __USE_GNU 1
33#include <stdio.h> 33#include <stdio.h>
34#include <ctype.h> 34#include <ctype.h>
35
36#ifndef _MSC_VER
35#include <unistd.h> 37#include <unistd.h>
38#endif
39
36#include <plist/plist.h> 40#include <plist/plist.h>
37#include <libimobiledevice-glue/utils.h> 41#include <libimobiledevice-glue/utils.h>
38 42
@@ -43,7 +47,7 @@
43#include "common/userpref.h" 47#include "common/userpref.h"
44#include "asprintf.h" 48#include "asprintf.h"
45 49
46#ifdef WIN32 50#ifdef _WIN32
47#include <windows.h> 51#include <windows.h>
48#define sleep(x) Sleep(x*1000) 52#define sleep(x) Sleep(x*1000)
49#endif 53#endif
@@ -617,6 +621,7 @@ lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *cli
617 .port = 0xf27e, 621 .port = 0xf27e,
618 .ssl_enabled = 0 622 .ssl_enabled = 0
619 }; 623 };
624 char *type = NULL;
620 625
621 property_list_service_client_t plistclient = NULL; 626 property_list_service_client_t plistclient = NULL;
622 if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { 627 if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
@@ -638,51 +643,32 @@ lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *cli
638 643
639 client_loc->label = label ? strdup(label) : NULL; 644 client_loc->label = label ? strdup(label) : NULL;
640 645
641 *client = client_loc; 646 int is_lockdownd = 0;
642 647 if (lockdownd_query_type(client_loc, &type) != LOCKDOWN_E_SUCCESS) {
643 return LOCKDOWN_E_SUCCESS;
644}
645
646lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label)
647{
648 if (!client)
649 return LOCKDOWN_E_INVALID_ARG;
650
651 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
652 lockdownd_client_t client_loc = NULL;
653 plist_t pair_record = NULL;
654 char *host_id = NULL;
655 char *type = NULL;
656
657 ret = lockdownd_client_new(device, &client_loc, label);
658 if (LOCKDOWN_E_SUCCESS != ret) {
659 debug_info("failed to create lockdownd client.");
660 return ret;
661 }
662
663 /* perform handshake */
664 ret = lockdownd_query_type(client_loc, &type);
665 if (LOCKDOWN_E_SUCCESS != ret) {
666 debug_info("QueryType failed in the lockdownd client."); 648 debug_info("QueryType failed in the lockdownd client.");
667 } else if (strcmp("com.apple.mobile.lockdown", type) != 0) { 649 } else if (!strcmp("com.apple.mobile.lockdown", type)) {
668 debug_info("Warning QueryType request returned \"%s\".", type); 650 is_lockdownd = 1;
651 } else {
652 debug_info("QueryType request returned \"%s\"", type);
669 } 653 }
670 free(type); 654 free(type);
671 655
672 if (device->version == 0) { 656 *client = client_loc;
657
658 if (is_lockdownd && device->version == 0) {
673 plist_t p_version = NULL; 659 plist_t p_version = NULL;
674 if (lockdownd_get_value(client_loc, NULL, "ProductVersion", &p_version) == LOCKDOWN_E_SUCCESS) { 660 if (lockdownd_get_value(client_loc, NULL, "ProductVersion", &p_version) == LOCKDOWN_E_SUCCESS) {
675 int vers[3] = {0, 0, 0}; 661 int vers[3] = {0, 0, 0};
676 char *s_version = NULL; 662 char *s_version = NULL;
677 plist_get_string_val(p_version, &s_version); 663 plist_get_string_val(p_version, &s_version);
678 if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) { 664 if (s_version && sscanf(s_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
679 device->version = DEVICE_VERSION(vers[0], vers[1], vers[2]); 665 device->version = IDEVICE_DEVICE_VERSION(vers[0], vers[1], vers[2]);
680 } 666 }
681 free(s_version); 667 free(s_version);
682 } 668 }
683 plist_free(p_version); 669 plist_free(p_version);
684 } 670 }
685 if (device->device_class == 0) { 671 if (is_lockdownd && device->device_class == 0) {
686 plist_t p_device_class = NULL; 672 plist_t p_device_class = NULL;
687 if (lockdownd_get_value(client_loc, NULL, "DeviceClass", &p_device_class) == LOCKDOWN_E_SUCCESS) { 673 if (lockdownd_get_value(client_loc, NULL, "DeviceClass", &p_device_class) == LOCKDOWN_E_SUCCESS) {
688 char* s_device_class = NULL; 674 char* s_device_class = NULL;
@@ -707,6 +693,26 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown
707 plist_free(p_device_class); 693 plist_free(p_device_class);
708 } 694 }
709 695
696 return LOCKDOWN_E_SUCCESS;
697}
698
699lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label)
700{
701 if (!client)
702 return LOCKDOWN_E_INVALID_ARG;
703
704 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
705 lockdownd_client_t client_loc = NULL;
706 plist_t pair_record = NULL;
707 char *host_id = NULL;
708
709 ret = lockdownd_client_new(device, &client_loc, label);
710 if (LOCKDOWN_E_SUCCESS != ret) {
711 debug_info("failed to create lockdownd client.");
712 return ret;
713 }
714
715 /* perform handshake */
710 userpref_error_t uerr = userpref_read_pair_record(client_loc->device->udid, &pair_record); 716 userpref_error_t uerr = userpref_read_pair_record(client_loc->device->udid, &pair_record);
711 if (uerr == USERPREF_E_READ_ERROR) { 717 if (uerr == USERPREF_E_READ_ERROR) {
712 debug_info("ERROR: Failed to retrieve pair record for %s", client_loc->device->udid); 718 debug_info("ERROR: Failed to retrieve pair record for %s", client_loc->device->udid);
@@ -730,7 +736,7 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown
730 plist_free(pair_record); 736 plist_free(pair_record);
731 pair_record = NULL; 737 pair_record = NULL;
732 738
733 if (device->version < DEVICE_VERSION(7,0,0) && device->device_class != DEVICE_CLASS_WATCH) { 739 if (device->version < IDEVICE_DEVICE_VERSION(7,0,0) && device->device_class != DEVICE_CLASS_WATCH) {
734 /* for older devices, we need to validate pairing to receive trusted host status */ 740 /* for older devices, we need to validate pairing to receive trusted host status */
735 ret = lockdownd_validate_pair(client_loc, NULL); 741 ret = lockdownd_validate_pair(client_loc, NULL);
736 742
@@ -836,7 +842,7 @@ static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t
836 842
837 /* generate keys and certificates into pair record */ 843 /* generate keys and certificates into pair record */
838 userpref_error_t uret = USERPREF_E_SUCCESS; 844 userpref_error_t uret = USERPREF_E_SUCCESS;
839 uret = pair_record_generate_keys_and_certs(*pair_record, public_key); 845 uret = pair_record_generate_keys_and_certs(*pair_record, public_key, client->device->version);
840 switch(uret) { 846 switch(uret) {
841 case USERPREF_E_INVALID_ARG: 847 case USERPREF_E_INVALID_ARG:
842 ret = LOCKDOWN_E_INVALID_ARG; 848 ret = LOCKDOWN_E_INVALID_ARG;
@@ -846,6 +852,7 @@ static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t
846 break; 852 break;
847 case USERPREF_E_SSL_ERROR: 853 case USERPREF_E_SSL_ERROR:
848 ret = LOCKDOWN_E_SSL_ERROR; 854 ret = LOCKDOWN_E_SSL_ERROR;
855 break;
849 default: 856 default:
850 break; 857 break;
851 } 858 }
diff --git a/src/misagent.c b/src/misagent.c
index e3da997..3fdca4d 100644
--- a/src/misagent.c
+++ b/src/misagent.c
@@ -24,9 +24,13 @@
24#endif 24#endif
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <stdio.h>
28
29#ifndef _MSC_VER
27#include <unistd.h> 30#include <unistd.h>
31#endif
32
28#include <plist/plist.h> 33#include <plist/plist.h>
29#include <stdio.h>
30 34
31#include "misagent.h" 35#include "misagent.h"
32#include "property_list_service.h" 36#include "property_list_service.h"
diff --git a/src/mobile_image_mounter.c b/src/mobile_image_mounter.c
index 6df50c4..6677882 100644
--- a/src/mobile_image_mounter.c
+++ b/src/mobile_image_mounter.c
@@ -24,7 +24,11 @@
24#endif 24#endif
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27
28#ifndef _MSC_VER
27#include <unistd.h> 29#include <unistd.h>
30#endif
31
28#include <plist/plist.h> 32#include <plist/plist.h>
29 33
30#include "mobile_image_mounter.h" 34#include "mobile_image_mounter.h"
diff --git a/src/notification_proxy.c b/src/notification_proxy.c
index 60b2e03..c7e4660 100644
--- a/src/notification_proxy.c
+++ b/src/notification_proxy.c
@@ -24,14 +24,19 @@
24#endif 24#endif
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27
28#ifndef _MSC_VER
27#include <unistd.h> 29#include <unistd.h>
30#endif
31
28#include <plist/plist.h> 32#include <plist/plist.h>
29 33
30#include "notification_proxy.h" 34#include "notification_proxy.h"
31#include "property_list_service.h" 35#include "property_list_service.h"
32#include "common/debug.h" 36#include "common/debug.h"
33 37
34#ifdef WIN32 38#ifdef _WIN32
39#include <windows.h>
35#define sleep(x) Sleep(x*1000) 40#define sleep(x) Sleep(x*1000)
36#endif 41#endif
37 42
@@ -109,7 +114,7 @@ np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t servic
109 114
110np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label) 115np_error_t np_client_start_service(idevice_t device, np_client_t* client, const char* label)
111{ 116{
112 np_error_t err = NP_E_UNKNOWN_ERROR; 117 int32_t err = NP_E_UNKNOWN_ERROR;
113 service_client_factory_start_service(device, NP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(np_client_new), &err); 118 service_client_factory_start_service(device, NP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(np_client_new), &err);
114 return err; 119 return err;
115} 120}
diff --git a/src/ostrace.c b/src/ostrace.c
new file mode 100644
index 0000000..68eb6bf
--- /dev/null
+++ b/src/ostrace.c
@@ -0,0 +1,436 @@
1/*
2 * ostrace.c
3 * com.apple.os_trace_relay service implementation.
4 *
5 * Copyright (c) 2020-2025 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25#include <string.h>
26#include <stdlib.h>
27
28#include <plist/plist.h>
29
30#include "ostrace.h"
31#include "lockdown.h"
32#include "common/debug.h"
33#include "endianness.h"
34
35struct ostrace_worker_thread {
36 ostrace_client_t client;
37 ostrace_activity_cb_t cbfunc;
38 void *user_data;
39};
40
41/**
42 * Convert a service_error_t value to a ostrace_error_t value.
43 * Used internally to get correct error codes.
44 *
45 * @param err An service_error_t error code
46 *
47 * @return A matching ostrace_error_t error code,
48 * OSTRACE_E_UNKNOWN_ERROR otherwise.
49 */
50static ostrace_error_t ostrace_error(service_error_t err)
51{
52 switch (err) {
53 case SERVICE_E_SUCCESS:
54 return OSTRACE_E_SUCCESS;
55 case SERVICE_E_INVALID_ARG:
56 return OSTRACE_E_INVALID_ARG;
57 case SERVICE_E_MUX_ERROR:
58 return OSTRACE_E_MUX_ERROR;
59 case SERVICE_E_SSL_ERROR:
60 return OSTRACE_E_SSL_ERROR;
61 case SERVICE_E_NOT_ENOUGH_DATA:
62 return OSTRACE_E_NOT_ENOUGH_DATA;
63 case SERVICE_E_TIMEOUT:
64 return OSTRACE_E_TIMEOUT;
65 default:
66 break;
67 }
68 return OSTRACE_E_UNKNOWN_ERROR;
69}
70
71ostrace_error_t ostrace_client_new(idevice_t device, lockdownd_service_descriptor_t service, ostrace_client_t * client)
72{
73 *client = NULL;
74
75 if (!device || !service || service->port == 0 || !client || *client) {
76 debug_info("Incorrect parameter passed to ostrace_client_new.");
77 return OSTRACE_E_INVALID_ARG;
78 }
79
80 debug_info("Creating ostrace_client, port = %d.", service->port);
81
82 service_client_t parent = NULL;
83 ostrace_error_t ret = ostrace_error(service_client_new(device, service, &parent));
84 if (ret != OSTRACE_E_SUCCESS) {
85 debug_info("Creating base service client failed. Error: %i", ret);
86 return ret;
87 }
88
89 ostrace_client_t client_loc = (ostrace_client_t) malloc(sizeof(struct ostrace_client_private));
90 client_loc->parent = parent;
91 client_loc->worker = THREAD_T_NULL;
92
93 *client = client_loc;
94
95 debug_info("ostrace_client successfully created.");
96 return 0;
97}
98
99ostrace_error_t ostrace_client_start_service(idevice_t device, ostrace_client_t * client, const char* label)
100{
101 ostrace_error_t err = OSTRACE_E_UNKNOWN_ERROR;
102 service_client_factory_start_service(device, OSTRACE_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(ostrace_client_new), &err);
103 return err;
104}
105
106ostrace_error_t ostrace_client_free(ostrace_client_t client)
107{
108 if (!client)
109 return OSTRACE_E_INVALID_ARG;
110 ostrace_stop_activity(client);
111 ostrace_error_t err = ostrace_error(service_client_free(client->parent));
112 free(client);
113
114 return err;
115}
116
117static ostrace_error_t ostrace_send_plist(ostrace_client_t client, plist_t plist)
118{
119 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
120 uint32_t blen = 0;
121 char* bin = NULL;
122 uint32_t sent = 0;
123 uint32_t swapped_len = 0;
124
125 if (!client || !plist) {
126 return OSTRACE_E_INVALID_ARG;
127 }
128
129 plist_to_bin(plist, &bin, &blen);
130 swapped_len = htobe32(blen);
131
132 res = ostrace_error(service_send(client->parent, (char*)&swapped_len, 4, &sent));
133 if (res == OSTRACE_E_SUCCESS) {
134 res = ostrace_error(service_send(client->parent, bin, blen, &sent));
135 }
136 free(bin);
137 return res;
138}
139
140static ostrace_error_t ostrace_receive_plist(ostrace_client_t client, plist_t *plist)
141{
142 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
143 uint8_t msgtype = 0;
144 uint32_t received = 0;
145 res = ostrace_error(service_receive(client->parent, (char*)&msgtype, 1, &received));
146 if (res != OSTRACE_E_SUCCESS) {
147 debug_info("Failed to read message type from service");
148 return res;
149 }
150 uint32_t rlen = 0;
151 res = ostrace_error(service_receive(client->parent, (char*)&rlen, 4, &received));
152 if (res != OSTRACE_E_SUCCESS) {
153 debug_info("Failed to read message size from service");
154 return res;
155 }
156
157 if (msgtype == 1) {
158 rlen = be32toh(rlen);
159 } else if (msgtype == 2) {
160 rlen = le32toh(rlen);
161 } else {
162 debug_info("Unexpected message type %d", msgtype);
163 return OSTRACE_E_UNKNOWN_ERROR;
164 }
165 debug_info("got length %d", rlen);
166
167 char* buf = (char*)malloc(rlen);
168 res = ostrace_error(service_receive(client->parent, buf, rlen, &received));
169 if (res != OSTRACE_E_SUCCESS) {
170 return res;
171 }
172
173 plist_t reply = NULL;
174 plist_err_t perr = plist_from_memory(buf, received, &reply, NULL);
175 free(buf);
176 if (perr != PLIST_ERR_SUCCESS) {
177 return OSTRACE_E_UNKNOWN_ERROR;
178 }
179 *plist = reply;
180 return OSTRACE_E_SUCCESS;
181}
182
183static ostrace_error_t _ostrace_check_result(plist_t reply)
184{
185 ostrace_error_t res = OSTRACE_E_REQUEST_FAILED;
186 if (!reply) {
187 return res;
188 }
189 plist_t p_status = plist_dict_get_item(reply, "Status");
190 if (!p_status) {
191 return res;
192 }
193 const char* status = plist_get_string_ptr(p_status, NULL);
194 if (!status) {
195 return res;
196 }
197 if (!strcmp(status, "RequestSuccessful")) {
198 res = OSTRACE_E_SUCCESS;
199 }
200 return res;
201}
202
203void *ostrace_worker(void *arg)
204{
205 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
206 struct ostrace_worker_thread *oswt = (struct ostrace_worker_thread*)arg;
207
208 if (!oswt)
209 return NULL;
210
211 uint8_t msgtype = 0;
212 uint32_t received = 0;
213
214 debug_info("Running");
215
216 while (oswt->client->parent) {
217 res = ostrace_error(service_receive_with_timeout(oswt->client->parent, (char*)&msgtype, 1, &received, 100));
218 if (res == OSTRACE_E_TIMEOUT) {
219 continue;
220 }
221 if (res != OSTRACE_E_SUCCESS) {
222 debug_info("Failed to read message type from service");
223 break;
224 }
225 uint32_t rlen = 0;
226 res = ostrace_error(service_receive(oswt->client->parent, (char*)&rlen, 4, &received));
227 if (res != OSTRACE_E_SUCCESS) {
228 debug_info("Failed to read message size from service");
229 break;
230 }
231
232 if (msgtype == 1) {
233 rlen = be32toh(rlen);
234 } else if (msgtype == 2) {
235 rlen = le32toh(rlen);
236 } else {
237 debug_info("Unexpected message type %d", msgtype);
238 break;
239 }
240
241 debug_info("got length %d", rlen);
242
243 void* buf = malloc(rlen);
244 res = ostrace_error(service_receive(oswt->client->parent, (char*)buf, rlen, &received));
245 if (res != OSTRACE_E_SUCCESS) {
246 debug_info("Failed to receive %d bytes, error %d", rlen, res);
247 break;
248 }
249 if (received < rlen) {
250 debug_info("Failed to receive all data, got %d/%d", received, rlen);
251 break;
252 }
253 oswt->cbfunc(buf, received, oswt->user_data);
254 }
255
256 if (oswt) {
257 free(oswt);
258 }
259
260 debug_info("Exiting");
261
262 return NULL;
263}
264
265ostrace_error_t ostrace_start_activity(ostrace_client_t client, plist_t options, ostrace_activity_cb_t callback, void* user_data)
266{
267 if (!client || !callback)
268 return OSTRACE_E_INVALID_ARG;
269
270 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
271
272 if (client->worker) {
273 debug_info("Another ostrace activity thread appears to be running already.");
274 return res;
275 }
276
277 plist_t dict = plist_new_dict();
278 plist_dict_set_item(dict, "Pid", plist_new_uint(0x0FFFFFFFF));
279 plist_dict_set_item(dict, "MessageFilter", plist_new_uint(0xFFFF));
280 plist_dict_set_item(dict, "StreamFlags", plist_new_uint(0x3C));
281 if (options) {
282 plist_dict_merge(&dict, options);
283 }
284 plist_dict_set_item(dict, "Request", plist_new_string("StartActivity"));
285
286 res = ostrace_send_plist(client, dict);
287 plist_free(dict);
288 if (res != OSTRACE_E_SUCCESS) {
289 return res;
290 }
291
292 dict = NULL;
293 res = ostrace_receive_plist(client, &dict);
294 if (res != OSTRACE_E_SUCCESS) {
295 return res;
296 }
297 res = _ostrace_check_result(dict);
298 if (res != OSTRACE_E_SUCCESS) {
299 return res;
300 }
301
302 /* start worker thread */
303 struct ostrace_worker_thread *oswt = (struct ostrace_worker_thread*)malloc(sizeof(struct ostrace_worker_thread));
304 if (oswt) {
305 oswt->client = client;
306 oswt->cbfunc = callback;
307 oswt->user_data = user_data;
308
309 if (thread_new(&client->worker, ostrace_worker, oswt) == 0) {
310 res = OSTRACE_E_SUCCESS;
311 }
312 }
313
314 return res;
315}
316
317ostrace_error_t ostrace_stop_activity(ostrace_client_t client)
318{
319 if (client->worker) {
320 /* notify thread to finish */
321 service_client_t parent = client->parent;
322 client->parent = NULL;
323 /* join thread to make it exit */
324 thread_join(client->worker);
325 thread_free(client->worker);
326 client->worker = THREAD_T_NULL;
327 client->parent = parent;
328 }
329
330 return OSTRACE_E_SUCCESS;
331}
332
333ostrace_error_t ostrace_get_pid_list(ostrace_client_t client, plist_t* list)
334{
335 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
336 plist_t dict = plist_new_dict();
337 plist_dict_set_item(dict, "Request", plist_new_string("PidList"));
338
339 if (!client || !list) {
340 return OSTRACE_E_INVALID_ARG;
341 }
342
343 res = ostrace_send_plist(client, dict);
344 plist_free(dict);
345 if (res != OSTRACE_E_SUCCESS) {
346 return res;
347 }
348
349 plist_t reply = NULL;
350 res = ostrace_receive_plist(client, &reply);
351 if (res != OSTRACE_E_SUCCESS) {
352 return res;
353 }
354 res = _ostrace_check_result(reply);
355 if (res != OSTRACE_E_SUCCESS) {
356 return res;
357 }
358
359 plist_t payload = plist_dict_get_item(reply, "Payload");
360 if (!payload) {
361 return OSTRACE_E_REQUEST_FAILED;
362 }
363 *list = plist_copy(payload);
364 plist_free(reply);
365
366 return OSTRACE_E_SUCCESS;
367}
368
369ostrace_error_t ostrace_create_archive(ostrace_client_t client, plist_t options, ostrace_archive_write_cb_t callback, void* user_data)
370{
371 ostrace_error_t res = OSTRACE_E_UNKNOWN_ERROR;
372 if (!client || !callback) {
373 return OSTRACE_E_INVALID_ARG;
374 }
375 plist_t dict = plist_new_dict();
376 if (options) {
377 plist_dict_merge(&dict, options);
378 }
379 plist_dict_set_item(dict, "Request", plist_new_string("CreateArchive"));
380
381 res = ostrace_send_plist(client, dict);
382 plist_free(dict);
383 if (res != OSTRACE_E_SUCCESS) {
384 return res;
385 }
386
387 plist_t reply = NULL;
388 res = ostrace_receive_plist(client, &reply);
389 if (res != OSTRACE_E_SUCCESS) {
390 return res;
391 }
392
393 res = _ostrace_check_result(reply);
394 if (res != OSTRACE_E_SUCCESS) {
395 return res;
396 }
397
398 debug_info("Receiving archive...\n");
399 while (1) {
400 uint8_t msgtype = 0;
401 uint32_t received = 0;
402 res = ostrace_error(service_receive(client->parent, (char*)&msgtype, 1, &received));
403 if (res != OSTRACE_E_SUCCESS) {
404 debug_info("Could not read message type from service: %d", res);
405 break;
406 }
407 if (msgtype != 3) {
408 debug_info("Unexpected packet type %d", msgtype);
409 return OSTRACE_E_REQUEST_FAILED;
410 }
411 uint32_t rlen = 0;
412 res = ostrace_error(service_receive(client->parent, (char*)&rlen, 4, &received));
413 if (res != OSTRACE_E_SUCCESS) {
414 debug_info("Failed to read message size from service");
415 break;
416 }
417
418 rlen = le32toh(rlen);
419 debug_info("got length %d", rlen);
420
421 unsigned char* buf = (unsigned char*)malloc(rlen);
422 res = ostrace_error(service_receive(client->parent, (char*)buf, rlen, &received));
423 if (res != OSTRACE_E_SUCCESS) {
424 debug_info("Could not read data from service: %d", res);
425 break;
426 }
427 if (callback(buf, received, user_data) < 0) {
428 debug_info("Aborted through callback");
429 return OSTRACE_E_REQUEST_FAILED;
430 }
431 }
432 debug_info("Done.\n");
433
434 return OSTRACE_E_SUCCESS;
435}
436
diff --git a/src/ostrace.h b/src/ostrace.h
new file mode 100644
index 0000000..dcc3e8d
--- /dev/null
+++ b/src/ostrace.h
@@ -0,0 +1,37 @@
1/*
2 * ostrace.h
3 * com.apple.os_trace_relay service header file.
4 *
5 * Copyright (c) 2020-2025 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef _OSTRACE_H
23#define _OSTRACE_H
24
25#include "idevice.h"
26#include "libimobiledevice/ostrace.h"
27#include "service.h"
28#include <libimobiledevice-glue/thread.h>
29
30struct ostrace_client_private {
31 service_client_t parent;
32 THREAD_T worker;
33};
34
35void *ostrace_worker(void *arg);
36
37#endif
diff --git a/src/sbservices.c b/src/sbservices.c
index 365e130..5df5122 100644
--- a/src/sbservices.c
+++ b/src/sbservices.c
@@ -24,7 +24,11 @@
24#endif 24#endif
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27
28#ifndef _MSC_VER
27#include <unistd.h> 29#include <unistd.h>
30#endif
31
28#include <plist/plist.h> 32#include <plist/plist.h>
29 33
30#include "sbservices.h" 34#include "sbservices.h"
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 7c9060b..24cfc66 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -35,7 +35,7 @@ bin_PROGRAMS = \
35 afcclient 35 afcclient
36 36
37idevicebtlogger_SOURCES = idevicebtlogger.c 37idevicebtlogger_SOURCES = idevicebtlogger.c
38iidevicebtlogger_CFLAGS = $(AM_CFLAGS) 38idevicebtlogger_CFLAGS = $(AM_CFLAGS)
39idevicebtlogger_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS) 39idevicebtlogger_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
40idevicebtlogger_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la 40idevicebtlogger_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
41 41
@@ -51,8 +51,8 @@ idevicename_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
51 51
52idevicepair_SOURCES = idevicepair.c 52idevicepair_SOURCES = idevicepair.c
53idevicepair_CFLAGS = $(AM_CFLAGS) 53idevicepair_CFLAGS = $(AM_CFLAGS)
54idevicepair_LDFLAGS = $(AM_LDFLAGS) $(libusbmuxd_LIBS) $(ssl_lib_LIBS) 54idevicepair_LDFLAGS = $(AM_LDFLAGS) $(libusbmuxd_LIBS)
55idevicepair_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la $(limd_glue_LIBS) 55idevicepair_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la $(limd_glue_LIBS) $(ssl_lib_LIBS)
56 56
57idevicesyslog_SOURCES = idevicesyslog.c 57idevicesyslog_SOURCES = idevicesyslog.c
58idevicesyslog_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) 58idevicesyslog_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS)
@@ -76,7 +76,7 @@ idevicebackup2_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
76 76
77ideviceimagemounter_SOURCES = ideviceimagemounter.c 77ideviceimagemounter_SOURCES = ideviceimagemounter.c
78ideviceimagemounter_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) $(libtatsu_CFLAGS) 78ideviceimagemounter_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) $(libtatsu_CFLAGS)
79ideviceimagemounter_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) $(ssl_lib_LIBS) $(libtatsu_LIBS) 79ideviceimagemounter_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) $(libtatsu_LIBS)
80ideviceimagemounter_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la 80ideviceimagemounter_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
81 81
82idevicescreenshot_SOURCES = idevicescreenshot.c 82idevicescreenshot_SOURCES = idevicescreenshot.c
@@ -135,8 +135,8 @@ idevicesetlocation_LDFLAGS = $(AM_LDFLAGS)
135idevicesetlocation_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la 135idevicesetlocation_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
136 136
137afcclient_SOURCES = afcclient.c 137afcclient_SOURCES = afcclient.c
138afcclient_CFLAGS = $(AM_CFLAGS) 138afcclient_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS)
139afcclient_LDFLAGS = $(AM_LDFLAGS) 139afcclient_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS)
140if HAVE_READLINE 140if HAVE_READLINE
141 afcclient_CFLAGS += $(readline_CFLAGS) 141 afcclient_CFLAGS += $(readline_CFLAGS)
142 afcclient_LDFLAGS += $(readline_LIBS) 142 afcclient_LDFLAGS += $(readline_LIBS)
diff --git a/tools/afcclient.c b/tools/afcclient.c
index 8f49831..2667e52 100644
--- a/tools/afcclient.c
+++ b/tools/afcclient.c
@@ -38,8 +38,9 @@
38#include <unistd.h> 38#include <unistd.h>
39#include <dirent.h> 39#include <dirent.h>
40#include <time.h> 40#include <time.h>
41#include <sys/stat.h>
41 42
42#ifdef WIN32 43#ifdef _WIN32
43#include <windows.h> 44#include <windows.h>
44#include <sys/time.h> 45#include <sys/time.h>
45#include <conio.h> 46#include <conio.h>
@@ -95,7 +96,7 @@ static size_t curdir_len = 0;
95static int file_exists(const char* path) 96static int file_exists(const char* path)
96{ 97{
97 struct stat tst; 98 struct stat tst;
98#ifdef WIN32 99#ifdef _WIN32
99 return (stat(path, &tst) == 0); 100 return (stat(path, &tst) == 0);
100#else 101#else
101 return (lstat(path, &tst) == 0); 102 return (lstat(path, &tst) == 0);
@@ -105,7 +106,7 @@ static int file_exists(const char* path)
105static int is_directory(const char* path) 106static int is_directory(const char* path)
106{ 107{
107 struct stat tst; 108 struct stat tst;
108#ifdef WIN32 109#ifdef _WIN32
109 return (stat(path, &tst) == 0) && S_ISDIR(tst.st_mode); 110 return (stat(path, &tst) == 0) && S_ISDIR(tst.st_mode);
110#else 111#else
111 return (lstat(path, &tst) == 0) && S_ISDIR(tst.st_mode); 112 return (lstat(path, &tst) == 0) && S_ISDIR(tst.st_mode);
@@ -138,8 +139,9 @@ static void print_usage(int argc, char **argv, int is_error)
138} 139}
139 140
140#ifndef HAVE_READLINE 141#ifndef HAVE_READLINE
141#ifdef WIN32 142#ifdef _WIN32
142#define BS_CC '\b' 143#define BS_CC '\b'
144#define getch _getch
143#else 145#else
144#define BS_CC 0x7f 146#define BS_CC 0x7f
145#define getch getchar 147#define getch getchar
@@ -154,12 +156,18 @@ static void get_input(char *buf, int maxlen)
154 break; 156 break;
155 } 157 }
156 if (isprint(c)) { 158 if (isprint(c)) {
157 if (len < maxlen-1) 159 if (len < maxlen-1) {
158 buf[len++] = c; 160 buf[len++] = c;
161#ifdef _WIN32
162 fputc(c, stdout);
163#endif
164 }
159 } else if (c == BS_CC) { 165 } else if (c == BS_CC) {
160 if (len > 0) { 166 if (len > 0) {
161 fputs("\b \b", stdout); 167 fputs("\b \b", stdout);
162 len--; 168 len--;
169 } else {
170 fputc(0x07, stdout);
163 } 171 }
164 } 172 }
165 } 173 }
@@ -175,7 +183,7 @@ int stop_requested = 0;
175static void handle_signal(int sig) 183static void handle_signal(int sig)
176{ 184{
177 stop_requested++; 185 stop_requested++;
178#ifdef WIN32 186#ifdef _WIN32
179 GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); 187 GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
180#else 188#else
181 kill(getpid(), SIGINT); 189 kill(getpid(), SIGINT);
@@ -364,62 +372,55 @@ static char* get_realpath(const char* path)
364 372
365static void handle_devinfo(afc_client_t afc, int argc, char** argv) 373static void handle_devinfo(afc_client_t afc, int argc, char** argv)
366{ 374{
367 char **info = NULL; 375 plist_t info = NULL;
368 afc_error_t err = afc_get_device_info(afc, &info); 376 afc_error_t err = afc_get_device_info_plist(afc, &info);
369 if (err == AFC_E_SUCCESS && info) { 377 if (err == AFC_E_SUCCESS && info) {
370 int i; 378 if (argc > 0 && !strcmp(argv[0], "--plain")) {
371 for (i = 0; info[i]; i += 2) { 379 plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE);
372 printf("%s: %s\n", info[i], info[i+1]); 380 } else {
381 plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE);
373 } 382 }
374 } else { 383 } else {
375 printf("Error: Failed to get device info: %s (%d)\n", afc_strerror(err), err); 384 printf("Error: Failed to get device info: %s (%d)\n", afc_strerror(err), err);
376 } 385 }
377 afc_dictionary_free(info); 386 plist_free(info);
378} 387}
379 388
380static int get_file_info_stat(afc_client_t afc, const char* path, struct afc_file_stat *stbuf) 389static int get_file_info_stat(afc_client_t afc, const char* path, struct afc_file_stat *stbuf)
381{ 390{
382 char **info = NULL; 391 plist_t info = NULL;
383 afc_error_t ret = afc_get_file_info(afc, path, &info); 392 afc_error_t ret = afc_get_file_info_plist(afc, path, &info);
384 memset(stbuf, 0, sizeof(struct afc_file_stat)); 393 memset(stbuf, 0, sizeof(struct afc_file_stat));
385 if (ret != AFC_E_SUCCESS) { 394 if (ret != AFC_E_SUCCESS) {
386 return -1; 395 return -1;
387 } else if (!info) { 396 } else if (!info) {
388 return -1; 397 return -1;
389 } else {
390 // get file attributes from info list
391 int i;
392 for (i = 0; info[i]; i += 2) {
393 if (!strcmp(info[i], "st_size")) {
394 stbuf->st_size = atoll(info[i+1]);
395 } else if (!strcmp(info[i], "st_blocks")) {
396 stbuf->st_blocks = atoi(info[i+1]);
397 } else if (!strcmp(info[i], "st_ifmt")) {
398 if (!strcmp(info[i+1], "S_IFREG")) {
399 stbuf->st_mode = S_IFREG;
400 } else if (!strcmp(info[i+1], "S_IFDIR")) {
401 stbuf->st_mode = S_IFDIR;
402 } else if (!strcmp(info[i+1], "S_IFLNK")) {
403 stbuf->st_mode = S_IFLNK;
404 } else if (!strcmp(info[i+1], "S_IFBLK")) {
405 stbuf->st_mode = S_IFBLK;
406 } else if (!strcmp(info[i+1], "S_IFCHR")) {
407 stbuf->st_mode = S_IFCHR;
408 } else if (!strcmp(info[i+1], "S_IFIFO")) {
409 stbuf->st_mode = S_IFIFO;
410 } else if (!strcmp(info[i+1], "S_IFSOCK")) {
411 stbuf->st_mode = S_IFSOCK;
412 }
413 } else if (!strcmp(info[i], "st_nlink")) {
414 stbuf->st_nlink = atoi(info[i+1]);
415 } else if (!strcmp(info[i], "st_mtime")) {
416 stbuf->st_mtime = (time_t)(atoll(info[i+1]) / 1000000000);
417 } else if (!strcmp(info[i], "st_birthtime")) { /* available on iOS 7+ */
418 stbuf->st_birthtime = (time_t)(atoll(info[i+1]) / 1000000000);
419 }
420 }
421 afc_dictionary_free(info);
422 } 398 }
399 stbuf->st_size = plist_dict_get_uint(info, "st_size");
400 stbuf->st_blocks = plist_dict_get_uint(info, "st_blocks");
401 const char* s_ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
402 if (s_ifmt) {
403 if (!strcmp(s_ifmt, "S_IFREG")) {
404 stbuf->st_mode = S_IFREG;
405 } else if (!strcmp(s_ifmt, "S_IFDIR")) {
406 stbuf->st_mode = S_IFDIR;
407 } else if (!strcmp(s_ifmt, "S_IFLNK")) {
408 stbuf->st_mode = S_IFLNK;
409 } else if (!strcmp(s_ifmt, "S_IFBLK")) {
410 stbuf->st_mode = S_IFBLK;
411 } else if (!strcmp(s_ifmt, "S_IFCHR")) {
412 stbuf->st_mode = S_IFCHR;
413 } else if (!strcmp(s_ifmt, "S_IFIFO")) {
414 stbuf->st_mode = S_IFIFO;
415 } else if (!strcmp(s_ifmt, "S_IFSOCK")) {
416 stbuf->st_mode = S_IFSOCK;
417 }
418 }
419 stbuf->st_nlink = plist_dict_get_uint(info, "st_nlink");
420 stbuf->st_mtime = (time_t)(plist_dict_get_uint(info, "st_mtime") / 1000000000);
421 /* available on iOS 7+ */
422 stbuf->st_birthtime = (time_t)(plist_dict_get_uint(info, "st_birthtime") / 1000000000);
423 plist_free(info);
423 return 0; 424 return 0;
424} 425}
425 426
@@ -430,22 +431,23 @@ static void handle_file_info(afc_client_t afc, int argc, char** argv)
430 return; 431 return;
431 } 432 }
432 433
433 char **info = NULL; 434 plist_t info = NULL;
434 char* abspath = get_absolute_path(argv[0]); 435 char* abspath = get_absolute_path(argv[0]);
435 if (!abspath) { 436 if (!abspath) {
436 printf("Error: Invalid argument\n"); 437 printf("Error: Invalid argument\n");
437 return; 438 return;
438 } 439 }
439 afc_error_t err = afc_get_file_info(afc, abspath, &info); 440 afc_error_t err = afc_get_file_info_plist(afc, abspath, &info);
440 if (err == AFC_E_SUCCESS && info) { 441 if (err == AFC_E_SUCCESS && info) {
441 int i; 442 if (argc > 1 && !strcmp(argv[1], "--plain")) {
442 for (i = 0; info[i]; i += 2) { 443 plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE);
443 printf("%s: %s\n", info[i], info[i+1]); 444 } else {
445 plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE);
444 } 446 }
445 } else { 447 } else {
446 printf("Error: Failed to get file info for %s: %s (%d)\n", argv[0], afc_strerror(err), err); 448 printf("Error: Failed to get file info for %s: %s (%d)\n", argv[0], afc_strerror(err), err);
447 } 449 }
448 afc_dictionary_free(info); 450 plist_free(info);
449 free(abspath); 451 free(abspath);
450} 452}
451 453
@@ -483,7 +485,7 @@ static void print_file_info(afc_client_t afc, const char* path, int list_verbose
483 printf(" "); 485 printf(" ");
484 printf("%10lld", (long long)st.st_size); 486 printf("%10lld", (long long)st.st_size);
485 printf(" "); 487 printf(" ");
486#ifdef WIN32 488#ifdef _WIN32
487 strftime(timebuf, 64, "%d %b %Y %H:%M:%S", localtime(&t)); 489 strftime(timebuf, 64, "%d %b %Y %H:%M:%S", localtime(&t));
488#else 490#else
489 strftime(timebuf, 64, "%d %h %Y %H:%M:%S", localtime(&t)); 491 strftime(timebuf, 64, "%d %h %Y %H:%M:%S", localtime(&t));
@@ -774,7 +776,7 @@ static uint8_t get_single_file(afc_client_t afc, const char *srcpath, const char
774 776
775static int __mkdir(const char* path) 777static int __mkdir(const char* path)
776{ 778{
777#ifdef WIN32 779#ifdef _WIN32
778 return mkdir(path); 780 return mkdir(path);
779#else 781#else
780 return mkdir(path, 0755); 782 return mkdir(path, 0755);
@@ -783,28 +785,19 @@ static int __mkdir(const char* path)
783 785
784static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_get) 786static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_get)
785{ 787{
786 char **info = NULL; 788 plist_t info = NULL;
787 uint64_t file_size = 0; 789 uint64_t file_size = 0;
788 afc_error_t err = afc_get_file_info(afc, srcpath, &info); 790 afc_error_t err = afc_get_file_info_plist(afc, srcpath, &info);
789 if (err == AFC_E_OBJECT_NOT_FOUND) { 791 if (err == AFC_E_OBJECT_NOT_FOUND) {
790 printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err); 792 printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
791 return 0; 793 return 0;
792 } 794 }
793 uint8_t is_dir = 0; 795 uint8_t is_dir = 0;
794 if (info) { 796 if (info) {
795 char **p = info; 797 file_size = plist_dict_get_uint(info, "st_size");
796 while (p && *p) { 798 const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
797 if (!strcmp(*p, "st_size")) { 799 is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
798 p++; 800 plist_free(info);
799 file_size = (uint64_t) strtoull(*p, NULL, 10);
800 }
801 if (!strcmp(*p, "st_ifmt")) {
802 p++;
803 is_dir = !strcmp(*p, "S_IFDIR");
804 }
805 p++;
806 }
807 afc_dictionary_free(info);
808 } 801 }
809 uint8_t succeed = 1; 802 uint8_t succeed = 1;
810 if (is_dir) { 803 if (is_dir) {
@@ -837,7 +830,7 @@ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpa
837 p++; 830 p++;
838 continue; 831 continue;
839 } 832 }
840 size_t len = srcpath_is_root ? strlen(*p) + 1 : srcpath_len + 1 + strlen(*p) + 1; 833 size_t len = srcpath_is_root ? (strlen(*p) + 2) : (srcpath_len + 1 + strlen(*p) + 1);
841 char *testpath = (char *) malloc(len); 834 char *testpath = (char *) malloc(len);
842 if (srcpath_is_root) { 835 if (srcpath_is_root) {
843 snprintf(testpath, len, "/%s", *p); 836 snprintf(testpath, len, "/%s", *p);
@@ -845,7 +838,7 @@ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpa
845 snprintf(testpath, len, "%s/%s", srcpath, *p); 838 snprintf(testpath, len, "%s/%s", srcpath, *p);
846 } 839 }
847 uint8_t dst_is_root = strcmp(srcpath, "/") == 0; 840 uint8_t dst_is_root = strcmp(srcpath, "/") == 0;
848 size_t dst_len = dst_is_root ? strlen(*p) + 1 : strlen(dstpath) + 1 + strlen(*p) + 1; 841 size_t dst_len = dst_is_root ? (strlen(*p) + 2) : (strlen(dstpath) + 1 + strlen(*p) + 1);
849 char *newdst = (char *) malloc(dst_len); 842 char *newdst = (char *) malloc(dst_len);
850 if (dst_is_root) { 843 if (dst_is_root) {
851 snprintf(newdst, dst_len, "/%s", *p); 844 snprintf(newdst, dst_len, "/%s", *p);
@@ -921,9 +914,9 @@ static void handle_get(afc_client_t afc, int argc, char **argv)
921 914
922 // target is a directory, put file under this target 915 // target is a directory, put file under this target
923 if (is_directory(dstpath)) { 916 if (is_directory(dstpath)) {
924 const char *basen = path_get_basename(argv[0]); 917 const char *basen = path_get_basename(srcpath);
925 uint8_t dst_is_root = strcmp(dstpath, "/") == 0; 918 uint8_t dst_is_root = strcmp(dstpath, "/") == 0;
926 size_t len = dst_is_root ? (strlen(basen) + 1) : (strlen(dstpath) + 1 + strlen(basen) + 1); 919 size_t len = dst_is_root ? (strlen(basen) + 2) : (strlen(dstpath) + 1 + strlen(basen) + 1);
927 char *newdst = (char *) malloc(len); 920 char *newdst = (char *) malloc(len);
928 if (dst_is_root) { 921 if (dst_is_root) {
929 snprintf(newdst, len, "/%s", basen); 922 snprintf(newdst, len, "/%s", basen);
@@ -944,11 +937,11 @@ static void handle_get(afc_client_t afc, int argc, char **argv)
944 937
945static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite) 938static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite)
946{ 939{
947 char **info = NULL; 940 plist_t info = NULL;
948 afc_error_t ret = afc_get_file_info(afc, dstpath, &info); 941 afc_error_t ret = afc_get_file_info_plist(afc, dstpath, &info);
949 // file exists, only overwrite with '-f' option was set 942 // file exists, only overwrite with '-f' option was set
950 if (ret == AFC_E_SUCCESS && info) { 943 if (ret == AFC_E_SUCCESS && info) {
951 afc_dictionary_free(info); 944 plist_free(info);
952 if (!force_overwrite) { 945 if (!force_overwrite) {
953 printf("Error: Failed to write into existing file without '-f' option: %s\n", dstpath); 946 printf("Error: Failed to write into existing file without '-f' option: %s\n", dstpath);
954 return 0; 947 return 0;
@@ -1016,6 +1009,9 @@ static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char
1016 } 1009 }
1017 } 1010 }
1018 } 1011 }
1012 if (progress) {
1013 printf("\n");
1014 }
1019 free(buf); 1015 free(buf);
1020 afc_file_close(afc, fh); 1016 afc_file_close(afc, fh);
1021 fclose(f); 1017 fclose(f);
@@ -1029,10 +1025,11 @@ static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpa
1029 printf("Error: Failed to put directory without '-r' option: %s\n", srcpath); 1025 printf("Error: Failed to put directory without '-r' option: %s\n", srcpath);
1030 return 0; 1026 return 0;
1031 } 1027 }
1032 char **info = NULL; 1028 plist_t info = NULL;
1033 afc_error_t err = afc_get_file_info(afc, dstpath, &info); 1029 afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info);
1034 //create if target directory does not exist 1030 //create if target directory does not exist
1035 afc_dictionary_free(info); 1031 plist_free(info);
1032 info = NULL;
1036 if (err == AFC_E_OBJECT_NOT_FOUND) { 1033 if (err == AFC_E_OBJECT_NOT_FOUND) {
1037 err = afc_make_directory(afc, dstpath); 1034 err = afc_make_directory(afc, dstpath);
1038 if (err != AFC_E_SUCCESS) { 1035 if (err != AFC_E_SUCCESS) {
@@ -1043,19 +1040,12 @@ static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpa
1043 printf("Error: Failed to put existing directory without '-f' option: %s\n", dstpath); 1040 printf("Error: Failed to put existing directory without '-f' option: %s\n", dstpath);
1044 return 0; 1041 return 0;
1045 } 1042 }
1046 afc_get_file_info(afc, dstpath, &info); 1043 afc_get_file_info_plist(afc, dstpath, &info);
1047 uint8_t is_dir = 0; 1044 uint8_t is_dir = 0;
1048 if (info) { 1045 if (info) {
1049 char **p = info; 1046 const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
1050 while (p && *p) { 1047 is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
1051 if (!strcmp(*p, "st_ifmt")) { 1048 plist_free(info);
1052 p++;
1053 is_dir = !strcmp(*p, "S_IFDIR");
1054 break;
1055 }
1056 p++;
1057 }
1058 afc_dictionary_free(info);
1059 } 1049 }
1060 if (!is_dir) { 1050 if (!is_dir) {
1061 printf("Error: Failed to create or access directory: '%s'\n", dstpath); 1051 printf("Error: Failed to create or access directory: '%s'\n", dstpath);
@@ -1073,7 +1063,7 @@ static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpa
1073 char *fpath = string_build_path(srcpath, ep->d_name, NULL); 1063 char *fpath = string_build_path(srcpath, ep->d_name, NULL);
1074 if (fpath) { 1064 if (fpath) {
1075 uint8_t dst_is_root = strcmp(dstpath, "/") == 0; 1065 uint8_t dst_is_root = strcmp(dstpath, "/") == 0;
1076 size_t len = dst_is_root ? strlen(ep->d_name) + 1 : strlen(dstpath) + 1 + strlen(ep->d_name) + 1; 1066 size_t len = dst_is_root ? (strlen(ep->d_name) + 2) : (strlen(dstpath) + 1 + strlen(ep->d_name) + 1);
1077 char *newdst = (char *) malloc(len); 1067 char *newdst = (char *) malloc(len);
1078 if (dst_is_root) { 1068 if (dst_is_root) {
1079 snprintf(newdst, len, "/%s", ep->d_name); 1069 snprintf(newdst, len, "/%s", ep->d_name);
@@ -1147,8 +1137,8 @@ static void handle_put(afc_client_t afc, int argc, char **argv)
1147 printf("Error: Invalid number of arguments\n"); 1137 printf("Error: Invalid number of arguments\n");
1148 return; 1138 return;
1149 } 1139 }
1150 char **info = NULL; 1140 plist_t info = NULL;
1151 afc_error_t err = afc_get_file_info(afc, dstpath, &info); 1141 afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info);
1152 // target does not exist, put directly 1142 // target does not exist, put directly
1153 if (err == AFC_E_OBJECT_NOT_FOUND) { 1143 if (err == AFC_E_OBJECT_NOT_FOUND) {
1154 put_file(afc, srcpath, dstpath, force_overwrite, recursive_put); 1144 put_file(afc, srcpath, dstpath, force_overwrite, recursive_put);
@@ -1157,22 +1147,15 @@ static void handle_put(afc_client_t afc, int argc, char **argv)
1157 } else { 1147 } else {
1158 uint8_t is_dir = 0; 1148 uint8_t is_dir = 0;
1159 if (info) { 1149 if (info) {
1160 char **p = info; 1150 const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
1161 while (p && *p) { 1151 is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
1162 if (!strcmp(*p, "st_ifmt")) { 1152 plist_free(info);
1163 p++;
1164 is_dir = !strcmp(*p, "S_IFDIR");
1165 break;
1166 }
1167 p++;
1168 }
1169 afc_dictionary_free(info);
1170 } 1153 }
1171 // target is a directory, try to put under this directory 1154 // target is a directory, try to put under this directory
1172 if (is_dir) { 1155 if (is_dir) {
1173 const char *basen = path_get_basename(srcpath); 1156 const char *basen = path_get_basename(srcpath);
1174 uint8_t dst_is_root = strcmp(dstpath, "/") == 0; 1157 uint8_t dst_is_root = strcmp(dstpath, "/") == 0;
1175 size_t len = dst_is_root ? strlen(basen) + 1 : strlen(dstpath) + 1 + strlen(basen) + 1; 1158 size_t len = dst_is_root ? (strlen(basen) + 2) : (strlen(dstpath) + 1 + strlen(basen) + 1);
1176 char *newdst = (char *) malloc(len); 1159 char *newdst = (char *) malloc(len);
1177 if (dst_is_root) { 1160 if (dst_is_root) {
1178 snprintf(newdst, len, "/%s", basen); 1161 snprintf(newdst, len, "/%s", basen);
@@ -1227,19 +1210,12 @@ static void handle_cd(afc_client_t afc, int argc, char** argv)
1227 1210
1228 char* path = get_realpath(argv[0]); 1211 char* path = get_realpath(argv[0]);
1229 int is_dir = 0; 1212 int is_dir = 0;
1230 char **info = NULL; 1213 plist_t info = NULL;
1231 afc_error_t err = afc_get_file_info(afc, path, &info); 1214 afc_error_t err = afc_get_file_info_plist(afc, path, &info);
1232 if (err == AFC_E_SUCCESS && info) { 1215 if (err == AFC_E_SUCCESS && info) {
1233 int i; 1216 const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
1234 for (i = 0; info[i]; i += 2) { 1217 is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
1235 if (!strcmp(info[i], "st_ifmt")) { 1218 plist_free(info);
1236 if (!strcmp(info[i+1], "S_IFDIR")) {
1237 is_dir = 1;
1238 }
1239 break;
1240 }
1241 }
1242 afc_dictionary_free(info);
1243 } else { 1219 } else {
1244 printf("Error: Failed to get file info for %s: %s (%d)\n", path, afc_strerror(err), err); 1220 printf("Error: Failed to get file info for %s: %s (%d)\n", path, afc_strerror(err), err);
1245 free(path); 1221 free(path);
@@ -1483,7 +1459,7 @@ int main(int argc, char** argv)
1483 }; 1459 };
1484 1460
1485 signal(SIGTERM, handle_signal); 1461 signal(SIGTERM, handle_signal);
1486#ifndef WIN32 1462#ifndef _WIN32
1487 signal(SIGQUIT, handle_signal); 1463 signal(SIGQUIT, handle_signal);
1488 signal(SIGPIPE, SIG_IGN); 1464 signal(SIGPIPE, SIG_IGN);
1489#endif 1465#endif
@@ -1561,7 +1537,7 @@ int main(int argc, char** argv)
1561 idevice_events_subscribe(&context, device_event_cb, NULL); 1537 idevice_events_subscribe(&context, device_event_cb, NULL);
1562 1538
1563 while (!connected && !stop_requested) { 1539 while (!connected && !stop_requested) {
1564#ifdef WIN32 1540#ifdef _WIN32
1565 Sleep(100); 1541 Sleep(100);
1566#else 1542#else
1567 usleep(100000); 1543 usleep(100000);
diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c
index c0537b8..363abad 100644
--- a/tools/idevicebackup.c
+++ b/tools/idevicebackup.c
@@ -35,6 +35,7 @@
35#include <unistd.h> 35#include <unistd.h>
36#include <ctype.h> 36#include <ctype.h>
37#include <time.h> 37#include <time.h>
38#include <sys/stat.h>
38 39
39#include <libimobiledevice/libimobiledevice.h> 40#include <libimobiledevice/libimobiledevice.h>
40#include <libimobiledevice/lockdown.h> 41#include <libimobiledevice/lockdown.h>
@@ -51,7 +52,7 @@
51#define LOCK_ATTEMPTS 50 52#define LOCK_ATTEMPTS 50
52#define LOCK_WAIT 200000 53#define LOCK_WAIT 200000
53 54
54#ifdef WIN32 55#ifdef _WIN32
55#include <windows.h> 56#include <windows.h>
56#define sleep(x) Sleep(x*1000) 57#define sleep(x) Sleep(x*1000)
57#endif 58#endif
@@ -175,7 +176,13 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid)
175 if (value_node) 176 if (value_node)
176 plist_dict_set_item(ret, "IMEI", plist_copy(value_node)); 177 plist_dict_set_item(ret, "IMEI", plist_copy(value_node));
177 178
178 plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0)); 179 plist_dict_set_item(ret, "Last Backup Date",
180#ifdef HAVE_PLIST_UNIX_DATE
181 plist_new_unix_date(time(NULL))
182#else
183 plist_new_date(time(NULL) - MAC_EPOCH, 0)
184#endif
185 );
179 186
180 value_node = plist_dict_get_item(root_node, "ProductType"); 187 value_node = plist_dict_get_item(root_node, "ProductType");
181 plist_dict_set_item(ret, "Product Type", plist_copy(value_node)); 188 plist_dict_set_item(ret, "Product Type", plist_copy(value_node));
@@ -212,7 +219,11 @@ static void mobilebackup_info_update_last_backup_date(plist_t info_plist)
212 return; 219 return;
213 220
214 node = plist_dict_get_item(info_plist, "Last Backup Date"); 221 node = plist_dict_get_item(info_plist, "Last Backup Date");
222#ifdef HAVE_PLIST_UNIX_DATE
223 plist_set_unix_date_val(node, time(NULL));
224#else
215 plist_set_date_val(node, time(NULL) - MAC_EPOCH, 0); 225 plist_set_date_val(node, time(NULL) - MAC_EPOCH, 0);
226#endif
216 227
217 node = NULL; 228 node = NULL;
218} 229}
@@ -642,7 +653,7 @@ int main(int argc, char *argv[])
642 /* we need to exit cleanly on running backups and restores or we cause havok */ 653 /* we need to exit cleanly on running backups and restores or we cause havok */
643 signal(SIGINT, clean_exit); 654 signal(SIGINT, clean_exit);
644 signal(SIGTERM, clean_exit); 655 signal(SIGTERM, clean_exit);
645#ifndef WIN32 656#ifndef _WIN32
646 signal(SIGQUIT, clean_exit); 657 signal(SIGQUIT, clean_exit);
647 signal(SIGPIPE, SIG_IGN); 658 signal(SIGPIPE, SIG_IGN);
648#endif 659#endif
@@ -1352,7 +1363,7 @@ files_out:
1352 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata"); 1363 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata");
1353 1364
1354 /* determine file size */ 1365 /* determine file size */
1355#ifdef WIN32 1366#ifdef _WIN32
1356 struct _stati64 fst; 1367 struct _stati64 fst;
1357 if (_stati64(file_info_path, &fst) != 0) 1368 if (_stati64(file_info_path, &fst) != 0)
1358#else 1369#else
diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c
index c73b269..12d6083 100644
--- a/tools/idevicebackup2.c
+++ b/tools/idevicebackup2.c
@@ -54,7 +54,7 @@
54#define LOCK_ATTEMPTS 50 54#define LOCK_ATTEMPTS 50
55#define LOCK_WAIT 200000 55#define LOCK_WAIT 200000
56 56
57#ifdef WIN32 57#ifdef _WIN32
58#include <windows.h> 58#include <windows.h>
59#include <conio.h> 59#include <conio.h>
60#define sleep(x) Sleep(x*1000) 60#define sleep(x) Sleep(x*1000)
@@ -74,6 +74,7 @@
74 74
75static int verbose = 1; 75static int verbose = 1;
76static int quit_flag = 0; 76static int quit_flag = 0;
77static int passcode_requested = 0;
77 78
78#define PRINT_VERBOSE(min_level, ...) if (verbose >= min_level) { printf(__VA_ARGS__); }; 79#define PRINT_VERBOSE(min_level, ...) if (verbose >= min_level) { printf(__VA_ARGS__); };
79 80
@@ -115,6 +116,10 @@ static void notify_cb(const char *notification, void *userdata)
115 quit_flag++; 116 quit_flag++;
116 } else if (!strcmp(notification, NP_BACKUP_DOMAIN_CHANGED)) { 117 } else if (!strcmp(notification, NP_BACKUP_DOMAIN_CHANGED)) {
117 backup_domain_changed = 1; 118 backup_domain_changed = 1;
119 } else if (!strcmp(notification, "com.apple.LocalAuthentication.ui.presented")) {
120 passcode_requested = 1;
121 } else if (!strcmp(notification, "com.apple.LocalAuthentication.ui.dismissed")) {
122 passcode_requested = 0;
118 } else { 123 } else {
119 PRINT_VERBOSE(1, "Unhandled notification '%s' (TODO: implement)\n", notification); 124 PRINT_VERBOSE(1, "Unhandled notification '%s' (TODO: implement)\n", notification);
120 } 125 }
@@ -126,21 +131,15 @@ static void mobilebackup_afc_get_file_contents(afc_client_t afc, const char *fil
126 return; 131 return;
127 } 132 }
128 133
129 char **fileinfo = NULL; 134 plist_t fileinfo = NULL;
130 uint32_t fsize = 0; 135 uint32_t fsize = 0;
131 136
132 afc_get_file_info(afc, filename, &fileinfo); 137 afc_get_file_info_plist(afc, filename, &fileinfo);
133 if (!fileinfo) { 138 if (!fileinfo) {
134 return; 139 return;
135 } 140 }
136 int i; 141 fsize = plist_dict_get_uint(fileinfo, "st_size");
137 for (i = 0; fileinfo[i]; i+=2) { 142 plist_free(fileinfo);
138 if (!strcmp(fileinfo[i], "st_size")) {
139 fsize = atol(fileinfo[i+1]);
140 break;
141 }
142 }
143 afc_dictionary_free(fileinfo);
144 143
145 if (fsize == 0) { 144 if (fsize == 0) {
146 return; 145 return;
@@ -173,7 +172,7 @@ static void mobilebackup_afc_get_file_contents(afc_client_t afc, const char *fil
173 172
174static int __mkdir(const char* path, int mode) 173static int __mkdir(const char* path, int mode)
175{ 174{
176#ifdef WIN32 175#ifdef _WIN32
177 return mkdir(path); 176 return mkdir(path);
178#else 177#else
179 return mkdir(path, mode); 178 return mkdir(path, mode);
@@ -202,7 +201,7 @@ static int mkdir_with_parents(const char *dir, int mode)
202 return res; 201 return res;
203} 202}
204 203
205#ifdef WIN32 204#ifdef _WIN32
206static int win32err_to_errno(int err_value) 205static int win32err_to_errno(int err_value)
207{ 206{
208 switch (err_value) { 207 switch (err_value) {
@@ -219,7 +218,7 @@ static int win32err_to_errno(int err_value)
219static int remove_file(const char* path) 218static int remove_file(const char* path)
220{ 219{
221 int e = 0; 220 int e = 0;
222#ifdef WIN32 221#ifdef _WIN32
223 if (!DeleteFile(path)) { 222 if (!DeleteFile(path)) {
224 e = win32err_to_errno(GetLastError()); 223 e = win32err_to_errno(GetLastError());
225 } 224 }
@@ -234,7 +233,7 @@ static int remove_file(const char* path)
234static int remove_directory(const char* path) 233static int remove_directory(const char* path)
235{ 234{
236 int e = 0; 235 int e = 0;
237#ifdef WIN32 236#ifdef _WIN32
238 if (!RemoveDirectory(path)) { 237 if (!RemoveDirectory(path)) {
239 e = win32err_to_errno(GetLastError()); 238 e = win32err_to_errno(GetLastError());
240 } 239 }
@@ -455,7 +454,13 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t d
455 /* Installed Applications */ 454 /* Installed Applications */
456 plist_dict_set_item(ret, "Installed Applications", installed_apps); 455 plist_dict_set_item(ret, "Installed Applications", installed_apps);
457 456
458 plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0)); 457 plist_dict_set_item(ret, "Last Backup Date",
458#ifdef HAVE_PLIST_UNIX_DATE
459 plist_new_unix_date(time(NULL))
460#else
461 plist_new_date(time(NULL) - MAC_EPOCH, 0)
462#endif
463 );
459 464
460 value_node = plist_dict_get_item(root_node, "MobileEquipmentIdentifier"); 465 value_node = plist_dict_get_item(root_node, "MobileEquipmentIdentifier");
461 if (value_node) 466 if (value_node)
@@ -768,7 +773,7 @@ static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char
768 uint32_t bytes = 0; 773 uint32_t bytes = 0;
769 char *localfile = string_build_path(backup_dir, path, NULL); 774 char *localfile = string_build_path(backup_dir, path, NULL);
770 char buf[32768]; 775 char buf[32768];
771#ifdef WIN32 776#ifdef _WIN32
772 struct _stati64 fst; 777 struct _stati64 fst;
773#else 778#else
774 struct stat fst; 779 struct stat fst;
@@ -779,7 +784,7 @@ static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char
779 int errcode = -1; 784 int errcode = -1;
780 int result = -1; 785 int result = -1;
781 uint32_t length; 786 uint32_t length;
782#ifdef WIN32 787#ifdef _WIN32
783 uint64_t total; 788 uint64_t total;
784 uint64_t sent; 789 uint64_t sent;
785#else 790#else
@@ -810,7 +815,7 @@ static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char
810 goto leave_proto_err; 815 goto leave_proto_err;
811 } 816 }
812 817
813#ifdef WIN32 818#ifdef _WIN32
814 if (_stati64(localfile, &fst) < 0) 819 if (_stati64(localfile, &fst) < 0)
815#else 820#else
816 if (stat(localfile, &fst) < 0) 821 if (stat(localfile, &fst) < 0)
@@ -1218,7 +1223,12 @@ static void mb2_handle_list_directory(mobilebackup2_client_t mobilebackup2, plis
1218 plist_dict_set_item(fdict, "DLFileType", plist_new_string(ftype)); 1223 plist_dict_set_item(fdict, "DLFileType", plist_new_string(ftype));
1219 plist_dict_set_item(fdict, "DLFileSize", plist_new_uint(st.st_size)); 1224 plist_dict_set_item(fdict, "DLFileSize", plist_new_uint(st.st_size));
1220 plist_dict_set_item(fdict, "DLFileModificationDate", 1225 plist_dict_set_item(fdict, "DLFileModificationDate",
1221 plist_new_date(st.st_mtime - MAC_EPOCH, 0)); 1226#ifdef HAVE_PLIST_UNIX_DATE
1227 plist_new_unix_date(st.st_mtime)
1228#else
1229 plist_new_date(st.st_mtime - MAC_EPOCH, 0)
1230#endif
1231 );
1222 1232
1223 plist_dict_set_item(dirlist, ep->d_name, fdict); 1233 plist_dict_set_item(dirlist, ep->d_name, fdict);
1224 free(fpath); 1234 free(fpath);
@@ -1343,7 +1353,7 @@ static void mb2_copy_directory_by_path(const char *src, const char *dst)
1343 } 1353 }
1344} 1354}
1345 1355
1346#ifdef WIN32 1356#ifdef _WIN32
1347#define BS_CC '\b' 1357#define BS_CC '\b'
1348#define my_getch getch 1358#define my_getch getch
1349#else 1359#else
@@ -1463,8 +1473,6 @@ static void print_usage(int argc, char **argv, int is_error)
1463 ); 1473 );
1464} 1474}
1465 1475
1466#define DEVICE_VERSION(maj, min, patch) ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF))
1467
1468int main(int argc, char *argv[]) 1476int main(int argc, char *argv[])
1469{ 1477{
1470 idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; 1478 idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
@@ -1530,7 +1538,7 @@ int main(int argc, char *argv[])
1530 /* we need to exit cleanly on running backups and restores or we cause havok */ 1538 /* we need to exit cleanly on running backups and restores or we cause havok */
1531 signal(SIGINT, clean_exit); 1539 signal(SIGINT, clean_exit);
1532 signal(SIGTERM, clean_exit); 1540 signal(SIGTERM, clean_exit);
1533#ifndef WIN32 1541#ifndef _WIN32
1534 signal(SIGQUIT, clean_exit); 1542 signal(SIGQUIT, clean_exit);
1535 signal(SIGPIPE, SIG_IGN); 1543 signal(SIGPIPE, SIG_IGN);
1536#endif 1544#endif
@@ -1844,34 +1852,20 @@ int main(int argc, char *argv[])
1844 } 1852 }
1845 1853
1846 /* get ProductVersion */ 1854 /* get ProductVersion */
1847 char *product_version = NULL; 1855 int device_version = idevice_get_device_version(device);
1848 int device_version = 0;
1849 node_tmp = NULL;
1850 lockdownd_get_value(lockdown, NULL, "ProductVersion", &node_tmp);
1851 if (node_tmp) {
1852 if (plist_get_node_type(node_tmp) == PLIST_STRING) {
1853 plist_get_string_val(node_tmp, &product_version);
1854 }
1855 plist_free(node_tmp);
1856 node_tmp = NULL;
1857 }
1858 if (product_version) {
1859 int vers[3] = { 0, 0, 0 };
1860 if (sscanf(product_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
1861 device_version = DEVICE_VERSION(vers[0], vers[1], vers[2]);
1862 }
1863 }
1864 1856
1865 /* start notification_proxy */ 1857 /* start notification_proxy */
1866 ldret = lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service); 1858 ldret = lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service);
1867 if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) { 1859 if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
1868 np_client_new(device, service, &np); 1860 np_client_new(device, service, &np);
1869 np_set_notify_callback(np, notify_cb, NULL); 1861 np_set_notify_callback(np, notify_cb, NULL);
1870 const char *noties[5] = { 1862 const char *noties[7] = {
1871 NP_SYNC_CANCEL_REQUEST, 1863 NP_SYNC_CANCEL_REQUEST,
1872 NP_SYNC_SUSPEND_REQUEST, 1864 NP_SYNC_SUSPEND_REQUEST,
1873 NP_SYNC_RESUME_REQUEST, 1865 NP_SYNC_RESUME_REQUEST,
1874 NP_BACKUP_DOMAIN_CHANGED, 1866 NP_BACKUP_DOMAIN_CHANGED,
1867 "com.apple.LocalAuthentication.ui.presented",
1868 "com.apple.LocalAuthentication.ui.dismissed",
1875 NULL 1869 NULL
1876 }; 1870 };
1877 np_observe_notifications(np, noties); 1871 np_observe_notifications(np, noties);
@@ -2058,6 +2052,16 @@ checkpoint:
2058 } else { 2052 } else {
2059 PRINT_VERBOSE(1, "Incremental backup mode.\n"); 2053 PRINT_VERBOSE(1, "Incremental backup mode.\n");
2060 } 2054 }
2055 if (device_version >= IDEVICE_DEVICE_VERSION(16,1,0)) {
2056 /* let's wait 2 second to see if the device passcode is requested */
2057 int retries = 20;
2058 while (retries-- > 0 && !passcode_requested) {
2059 usleep(100000);
2060 }
2061 if (passcode_requested) {
2062 printf("*** Waiting for passcode to be entered on the device ***\n");
2063 }
2064 }
2061 } else { 2065 } else {
2062 if (err == MOBILEBACKUP2_E_BAD_VERSION) { 2066 if (err == MOBILEBACKUP2_E_BAD_VERSION) {
2063 printf("ERROR: Could not start backup process: backup protocol version mismatch!\n"); 2067 printf("ERROR: Could not start backup process: backup protocol version mismatch!\n");
@@ -2229,7 +2233,7 @@ checkpoint:
2229 if (newpw || backup_password) { 2233 if (newpw || backup_password) {
2230 mobilebackup2_send_message(mobilebackup2, "ChangePassword", opts); 2234 mobilebackup2_send_message(mobilebackup2, "ChangePassword", opts);
2231 uint8_t passcode_hint = 0; 2235 uint8_t passcode_hint = 0;
2232 if (device_version >= DEVICE_VERSION(13,0,0)) { 2236 if (device_version >= IDEVICE_DEVICE_VERSION(13,0,0)) {
2233 diagnostics_relay_client_t diag = NULL; 2237 diagnostics_relay_client_t diag = NULL;
2234 if (diagnostics_relay_client_start_service(device, &diag, TOOL_NAME) == DIAGNOSTICS_RELAY_E_SUCCESS) { 2238 if (diagnostics_relay_client_start_service(device, &diag, TOOL_NAME) == DIAGNOSTICS_RELAY_E_SUCCESS) {
2235 plist_t dict = NULL; 2239 plist_t dict = NULL;
@@ -2307,7 +2311,7 @@ checkpoint:
2307 /* device wants to know how much disk space is available on the computer */ 2311 /* device wants to know how much disk space is available on the computer */
2308 uint64_t freespace = 0; 2312 uint64_t freespace = 0;
2309 int res = -1; 2313 int res = -1;
2310#ifdef WIN32 2314#ifdef _WIN32
2311 if (GetDiskFreeSpaceEx(backup_directory, (PULARGE_INTEGER)&freespace, NULL, NULL)) { 2315 if (GetDiskFreeSpaceEx(backup_directory, (PULARGE_INTEGER)&freespace, NULL, NULL)) {
2312 res = 0; 2316 res = 0;
2313 } 2317 }
@@ -2316,7 +2320,7 @@ checkpoint:
2316 memset(&fs, '\0', sizeof(fs)); 2320 memset(&fs, '\0', sizeof(fs));
2317 res = statvfs(backup_directory, &fs); 2321 res = statvfs(backup_directory, &fs);
2318 if (res == 0) { 2322 if (res == 0) {
2319 freespace = (uint64_t)fs.f_bavail * (uint64_t)fs.f_bsize; 2323 freespace = (uint64_t)fs.f_bavail * (uint64_t)fs.f_frsize;
2320 } 2324 }
2321#endif 2325#endif
2322 plist_t freespace_item = plist_new_uint(freespace); 2326 plist_t freespace_item = plist_new_uint(freespace);
diff --git a/tools/idevicebtlogger.c b/tools/idevicebtlogger.c
index 8de6b22..ca68b59 100644
--- a/tools/idevicebtlogger.c
+++ b/tools/idevicebtlogger.c
@@ -36,7 +36,7 @@
36#include <assert.h> 36#include <assert.h>
37#include <fcntl.h> 37#include <fcntl.h>
38 38
39#ifdef WIN32 39#ifdef _WIN32
40#include <windows.h> 40#include <windows.h>
41#define sleep(x) Sleep(x*1000) 41#define sleep(x) Sleep(x*1000)
42#else 42#else
@@ -334,7 +334,7 @@ int main(int argc, char *argv[])
334 334
335 signal(SIGINT, clean_exit); 335 signal(SIGINT, clean_exit);
336 signal(SIGTERM, clean_exit); 336 signal(SIGTERM, clean_exit);
337#ifndef WIN32 337#ifndef _WIN32
338 signal(SIGQUIT, clean_exit); 338 signal(SIGQUIT, clean_exit);
339 signal(SIGPIPE, SIG_IGN); 339 signal(SIGPIPE, SIG_IGN);
340#endif 340#endif
diff --git a/tools/idevicecrashreport.c b/tools/idevicecrashreport.c
index 09bd537..b9869ae 100644
--- a/tools/idevicecrashreport.c
+++ b/tools/idevicecrashreport.c
@@ -31,7 +31,8 @@
31#include <string.h> 31#include <string.h>
32#include <unistd.h> 32#include <unistd.h>
33#include <getopt.h> 33#include <getopt.h>
34#ifndef WIN32 34#include <sys/stat.h>
35#ifndef _WIN32
35#include <signal.h> 36#include <signal.h>
36#endif 37#endif
37#include <libimobiledevice-glue/utils.h> 38#include <libimobiledevice-glue/utils.h>
@@ -42,7 +43,7 @@
42#include <libimobiledevice/afc.h> 43#include <libimobiledevice/afc.h>
43#include <plist/plist.h> 44#include <plist/plist.h>
44 45
45#ifdef WIN32 46#ifdef _WIN32
46#include <windows.h> 47#include <windows.h>
47#define S_IFLNK S_IFREG 48#define S_IFLNK S_IFREG
48#define S_IFSOCK S_IFREG 49#define S_IFSOCK S_IFREG
@@ -54,11 +55,12 @@
54const char* target_directory = NULL; 55const char* target_directory = NULL;
55static int extract_raw_crash_reports = 0; 56static int extract_raw_crash_reports = 0;
56static int keep_crash_reports = 0; 57static int keep_crash_reports = 0;
58static int remove_all = 0;
57 59
58static int file_exists(const char* path) 60static int file_exists(const char* path)
59{ 61{
60 struct stat tst; 62 struct stat tst;
61#ifdef WIN32 63#ifdef _WIN32
62 return (stat(path, &tst) == 0); 64 return (stat(path, &tst) == 0);
63#else 65#else
64 return (lstat(path, &tst) == 0); 66 return (lstat(path, &tst) == 0);
@@ -144,7 +146,7 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char
144 continue; 146 continue;
145 } 147 }
146 148
147 char **fileinfo = NULL; 149 plist_t fileinfo = NULL;
148 struct stat stbuf; 150 struct stat stbuf;
149 memset(&stbuf, '\0', sizeof(struct stat)); 151 memset(&stbuf, '\0', sizeof(struct stat));
150 152
@@ -152,7 +154,7 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char
152 strcpy(((char*)source_filename) + device_directory_length, list[k]); 154 strcpy(((char*)source_filename) + device_directory_length, list[k]);
153 155
154 /* assemble absolute target filename */ 156 /* assemble absolute target filename */
155#ifdef WIN32 157#ifdef _WIN32
156 /* replace every ':' with '-' since ':' is an illegal character for file names in windows */ 158 /* replace every ':' with '-' since ':' is an illegal character for file names in windows */
157 char* current_pos = strchr(list[k], ':'); 159 char* current_pos = strchr(list[k], ':');
158 while (current_pos) { 160 while (current_pos) {
@@ -171,88 +173,93 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char
171 } 173 }
172 174
173 /* get file information */ 175 /* get file information */
174 afc_get_file_info(afc, source_filename, &fileinfo); 176 afc_get_file_info_plist(afc, source_filename, &fileinfo);
175 if (!fileinfo) { 177 if (!fileinfo) {
176 printf("Failed to read information for '%s'. Skipping...\n", source_filename); 178 printf("Failed to read information for '%s'. Skipping...\n", source_filename);
177 continue; 179 continue;
178 } 180 }
179 181
180 /* parse file information */ 182 /* parse file information */
181 int i; 183 stbuf.st_size = plist_dict_get_uint(fileinfo, "st_size");
182 for (i = 0; fileinfo[i]; i+=2) { 184 const char* s_ifmt = plist_get_string_ptr(plist_dict_get_item(fileinfo, "st_ifmt"), NULL);
183 if (!strcmp(fileinfo[i], "st_size")) { 185 if (s_ifmt) {
184 stbuf.st_size = atoll(fileinfo[i+1]); 186 if (!strcmp(s_ifmt, "S_IFREG")) {
185 } else if (!strcmp(fileinfo[i], "st_ifmt")) { 187 stbuf.st_mode = S_IFREG;
186 if (!strcmp(fileinfo[i+1], "S_IFREG")) { 188 } else if (!strcmp(s_ifmt, "S_IFDIR")) {
187 stbuf.st_mode = S_IFREG; 189 stbuf.st_mode = S_IFDIR;
188 } else if (!strcmp(fileinfo[i+1], "S_IFDIR")) { 190 } else if (!strcmp(s_ifmt, "S_IFLNK")) {
189 stbuf.st_mode = S_IFDIR; 191 stbuf.st_mode = S_IFLNK;
190 } else if (!strcmp(fileinfo[i+1], "S_IFLNK")) { 192 } else if (!strcmp(s_ifmt, "S_IFBLK")) {
191 stbuf.st_mode = S_IFLNK; 193 stbuf.st_mode = S_IFBLK;
192 } else if (!strcmp(fileinfo[i+1], "S_IFBLK")) { 194 } else if (!strcmp(s_ifmt, "S_IFCHR")) {
193 stbuf.st_mode = S_IFBLK; 195 stbuf.st_mode = S_IFCHR;
194 } else if (!strcmp(fileinfo[i+1], "S_IFCHR")) { 196 } else if (!strcmp(s_ifmt, "S_IFIFO")) {
195 stbuf.st_mode = S_IFCHR; 197 stbuf.st_mode = S_IFIFO;
196 } else if (!strcmp(fileinfo[i+1], "S_IFIFO")) { 198 } else if (!strcmp(s_ifmt, "S_IFSOCK")) {
197 stbuf.st_mode = S_IFIFO; 199 stbuf.st_mode = S_IFSOCK;
198 } else if (!strcmp(fileinfo[i+1], "S_IFSOCK")) { 200 }
199 stbuf.st_mode = S_IFSOCK; 201 }
200 } 202 stbuf.st_nlink = plist_dict_get_uint(fileinfo, "st_nlink");
201 } else if (!strcmp(fileinfo[i], "st_nlink")) { 203 stbuf.st_mtime = (time_t)(plist_dict_get_uint(fileinfo, "st_mtime") / 1000000000);
202 stbuf.st_nlink = atoi(fileinfo[i+1]); 204 const char* linktarget = plist_get_string_ptr(plist_dict_get_item(fileinfo, "LinkTarget"), NULL);
203 } else if (!strcmp(fileinfo[i], "st_mtime")) { 205 if (linktarget && !remove_all) {
204 stbuf.st_mtime = (time_t)(atoll(fileinfo[i+1]) / 1000000000); 206 /* report latest crash report filename */
205 } else if (!strcmp(fileinfo[i], "LinkTarget")) { 207 printf("Link: %s\n", (char*)target_filename + strlen(target_directory));
206 /* report latest crash report filename */ 208
207 printf("Link: %s\n", (char*)target_filename + strlen(target_directory)); 209 /* remove any previous symlink */
208 210 if (file_exists(target_filename)) {
209 /* remove any previous symlink */ 211 remove(target_filename);
210 if (file_exists(target_filename)) { 212 }
211 remove(target_filename);
212 }
213 213
214#ifndef WIN32 214#ifndef _WIN32
215 /* use relative filename */ 215 /* use relative filename */
216 char* b = strrchr(fileinfo[i+1], '/'); 216 const char* b = strrchr(linktarget, '/');
217 if (b == NULL) { 217 if (b == NULL) {
218 b = fileinfo[i+1]; 218 b = linktarget;
219 } else { 219 } else {
220 b++; 220 b++;
221 } 221 }
222 222
223 /* create a symlink pointing to latest log */ 223 /* create a symlink pointing to latest log */
224 if (symlink(b, target_filename) < 0) { 224 if (symlink(b, target_filename) < 0) {
225 fprintf(stderr, "Can't create symlink to %s\n", b); 225 fprintf(stderr, "Can't create symlink to %s\n", b);
226 } 226 }
227#endif 227#endif
228 228
229 if (!keep_crash_reports) 229 if (!keep_crash_reports)
230 afc_remove_path(afc, source_filename); 230 afc_remove_path(afc, source_filename);
231 231
232 res = 0; 232 res = 0;
233 }
234 } 233 }
235 234
236 /* free file information */ 235 /* free file information */
237 afc_dictionary_free(fileinfo); 236 plist_free(fileinfo);
238 237
239 /* recurse into child directories */ 238 /* recurse into child directories */
240 if (S_ISDIR(stbuf.st_mode)) { 239 if (S_ISDIR(stbuf.st_mode)) {
241#ifdef WIN32 240 if (!remove_all) {
242 mkdir(target_filename); 241#ifdef _WIN32
242 mkdir(target_filename);
243#else 243#else
244 mkdir(target_filename, 0755); 244 mkdir(target_filename, 0755);
245#endif 245#endif
246 }
246 res = afc_client_copy_and_remove_crash_reports(afc, source_filename, target_filename, filename_filter); 247 res = afc_client_copy_and_remove_crash_reports(afc, source_filename, target_filename, filename_filter);
247 248
248 /* remove directory from device */ 249 /* remove directory from device */
249 if (!keep_crash_reports) 250 if (!remove_all && !keep_crash_reports)
250 afc_remove_path(afc, source_filename); 251 afc_remove_path(afc, source_filename);
251 } else if (S_ISREG(stbuf.st_mode)) { 252 } else if (S_ISREG(stbuf.st_mode)) {
252 if (filename_filter != NULL && strstr(source_filename, filename_filter) == NULL) { 253 if (filename_filter != NULL && strstr(source_filename, filename_filter) == NULL) {
253 continue; 254 continue;
254 } 255 }
255 256
257 if (remove_all) {
258 printf("Remove: %s\n", source_filename);
259 afc_remove_path(afc, source_filename);
260 continue;
261 }
262
256 /* copy file to host */ 263 /* copy file to host */
257 afc_error = afc_file_open(afc, source_filename, AFC_FOPEN_RDONLY, &handle); 264 afc_error = afc_file_open(afc, source_filename, AFC_FOPEN_RDONLY, &handle);
258 if(afc_error != AFC_E_SUCCESS) { 265 if(afc_error != AFC_E_SUCCESS) {
@@ -331,6 +338,7 @@ static void print_usage(int argc, char **argv, int is_error)
331 " -f, --filter NAME filter crash reports by NAME (case sensitive)\n" 338 " -f, --filter NAME filter crash reports by NAME (case sensitive)\n"
332 " -h, --help prints usage information\n" 339 " -h, --help prints usage information\n"
333 " -v, --version prints version information\n" 340 " -v, --version prints version information\n"
341 " --remove-all remove all crash logs found\n"
334 "\n" 342 "\n"
335 "Homepage: <" PACKAGE_URL ">\n" 343 "Homepage: <" PACKAGE_URL ">\n"
336 "Bug Reports: <" PACKAGE_BUGREPORT ">\n" 344 "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
@@ -361,10 +369,11 @@ int main(int argc, char* argv[])
361 { "filter", required_argument, NULL, 'f' }, 369 { "filter", required_argument, NULL, 'f' },
362 { "extract", no_argument, NULL, 'e' }, 370 { "extract", no_argument, NULL, 'e' },
363 { "keep", no_argument, NULL, 'k' }, 371 { "keep", no_argument, NULL, 'k' },
372 { "remove-all", no_argument, NULL, 1 },
364 { NULL, 0, NULL, 0} 373 { NULL, 0, NULL, 0}
365 }; 374 };
366 375
367#ifndef WIN32 376#ifndef _WIN32
368 signal(SIGPIPE, SIG_IGN); 377 signal(SIGPIPE, SIG_IGN);
369#endif 378#endif
370 379
@@ -405,6 +414,9 @@ int main(int argc, char* argv[])
405 case 'k': 414 case 'k':
406 keep_crash_reports = 1; 415 keep_crash_reports = 1;
407 break; 416 break;
417 case 1:
418 remove_all = 1;
419 break;
408 default: 420 default:
409 print_usage(argc, argv, 1); 421 print_usage(argc, argv, 1);
410 return 2; 422 return 2;
@@ -414,12 +426,16 @@ int main(int argc, char* argv[])
414 argv += optind; 426 argv += optind;
415 427
416 /* ensure a target directory was supplied */ 428 /* ensure a target directory was supplied */
417 if (!argv[0]) { 429 if (!remove_all) {
418 fprintf(stderr, "ERROR: missing target directory.\n"); 430 if (!argv[0]) {
419 print_usage(argc+optind, argv-optind, 1); 431 fprintf(stderr, "ERROR: missing target directory.\n");
420 return 2; 432 print_usage(argc+optind, argv-optind, 1);
433 return 2;
434 }
435 target_directory = argv[0];
436 } else {
437 target_directory = ".";
421 } 438 }
422 target_directory = argv[0];
423 439
424 /* check if target directory exists */ 440 /* check if target directory exists */
425 if (!file_exists(target_directory)) { 441 if (!file_exists(target_directory)) {
diff --git a/tools/idevicedate.c b/tools/idevicedate.c
index d05f63e..31b0cf7 100644
--- a/tools/idevicedate.c
+++ b/tools/idevicedate.c
@@ -33,7 +33,7 @@
33#if HAVE_LANGINFO_CODESET 33#if HAVE_LANGINFO_CODESET
34#include <langinfo.h> 34#include <langinfo.h>
35#endif 35#endif
36#ifndef WIN32 36#ifndef _WIN32
37#include <signal.h> 37#include <signal.h>
38#endif 38#endif
39 39
@@ -43,7 +43,7 @@
43#ifdef _DATE_FMT 43#ifdef _DATE_FMT
44#define DATE_FMT_LANGINFO nl_langinfo (_DATE_FMT) 44#define DATE_FMT_LANGINFO nl_langinfo (_DATE_FMT)
45#else 45#else
46#ifdef WIN32 46#ifdef _WIN32
47#define DATE_FMT_LANGINFO "%a %b %#d %H:%M:%S %Z %Y" 47#define DATE_FMT_LANGINFO "%a %b %#d %H:%M:%S %Z %Y"
48#else 48#else
49#define DATE_FMT_LANGINFO "%a %b %e %H:%M:%S %Z %Y" 49#define DATE_FMT_LANGINFO "%a %b %e %H:%M:%S %Z %Y"
@@ -104,7 +104,7 @@ int main(int argc, char *argv[])
104 { NULL, 0, NULL, 0} 104 { NULL, 0, NULL, 0}
105 }; 105 };
106 106
107#ifndef WIN32 107#ifndef _WIN32
108 signal(SIGPIPE, SIG_IGN); 108 signal(SIGPIPE, SIG_IGN);
109#endif 109#endif
110 /* parse cmdline args */ 110 /* parse cmdline args */
diff --git a/tools/idevicedebug.c b/tools/idevicedebug.c
index 36c594e..3f2e289 100644
--- a/tools/idevicedebug.c
+++ b/tools/idevicedebug.c
@@ -34,7 +34,7 @@
34#include <libgen.h> 34#include <libgen.h>
35#include <getopt.h> 35#include <getopt.h>
36 36
37#ifdef WIN32 37#ifdef _WIN32
38#include <windows.h> 38#include <windows.h>
39#define sleep(x) Sleep(x*1000) 39#define sleep(x) Sleep(x*1000)
40#endif 40#endif
@@ -239,7 +239,7 @@ int main(int argc, char *argv[])
239 /* map signals */ 239 /* map signals */
240 signal(SIGINT, on_signal); 240 signal(SIGINT, on_signal);
241 signal(SIGTERM, on_signal); 241 signal(SIGTERM, on_signal);
242#ifndef WIN32 242#ifndef _WIN32
243 signal(SIGQUIT, on_signal); 243 signal(SIGQUIT, on_signal);
244 signal(SIGPIPE, SIG_IGN); 244 signal(SIGPIPE, SIG_IGN);
245#endif 245#endif
diff --git a/tools/idevicedebugserverproxy.c b/tools/idevicedebugserverproxy.c
index 9fe7051..fb082b3 100644
--- a/tools/idevicedebugserverproxy.c
+++ b/tools/idevicedebugserverproxy.c
@@ -32,7 +32,7 @@
32#include <getopt.h> 32#include <getopt.h>
33#include <errno.h> 33#include <errno.h>
34#include <signal.h> 34#include <signal.h>
35#ifdef WIN32 35#ifdef _WIN32
36#include <winsock2.h> 36#include <winsock2.h>
37#include <windows.h> 37#include <windows.h>
38#else 38#else
@@ -219,7 +219,7 @@ int main(int argc, char *argv[])
219 { NULL, 0, NULL, 0} 219 { NULL, 0, NULL, 0}
220 }; 220 };
221 221
222#ifndef WIN32 222#ifndef _WIN32
223 struct sigaction sa; 223 struct sigaction sa;
224 struct sigaction si; 224 struct sigaction si;
225 memset(&sa, '\0', sizeof(struct sigaction)); 225 memset(&sa, '\0', sizeof(struct sigaction));
diff --git a/tools/idevicedevmodectl.c b/tools/idevicedevmodectl.c
index bd1de6a..6bf1a1c 100644
--- a/tools/idevicedevmodectl.c
+++ b/tools/idevicedevmodectl.c
@@ -32,11 +32,11 @@
32#include <sys/stat.h> 32#include <sys/stat.h>
33#include <unistd.h> 33#include <unistd.h>
34#include <errno.h> 34#include <errno.h>
35#ifndef WIN32 35#ifndef _WIN32
36#include <signal.h> 36#include <signal.h>
37#endif 37#endif
38 38
39#ifdef WIN32 39#ifdef _WIN32
40#include <windows.h> 40#include <windows.h>
41#define __usleep(x) Sleep(x/1000) 41#define __usleep(x) Sleep(x/1000)
42#else 42#else
@@ -259,7 +259,7 @@ int main(int argc, char *argv[])
259 { NULL, 0, NULL, 0} 259 { NULL, 0, NULL, 0}
260 }; 260 };
261 261
262#ifndef WIN32 262#ifndef _WIN32
263 signal(SIGPIPE, SIG_IGN); 263 signal(SIGPIPE, SIG_IGN);
264#endif 264#endif
265 /* parse cmdline args */ 265 /* parse cmdline args */
diff --git a/tools/idevicediagnostics.c b/tools/idevicediagnostics.c
index e699bc4..365c0a4 100644
--- a/tools/idevicediagnostics.c
+++ b/tools/idevicediagnostics.c
@@ -31,7 +31,7 @@
31#include <getopt.h> 31#include <getopt.h>
32#include <errno.h> 32#include <errno.h>
33#include <time.h> 33#include <time.h>
34#ifndef WIN32 34#ifndef _WIN32
35#include <signal.h> 35#include <signal.h>
36#endif 36#endif
37 37
@@ -113,7 +113,7 @@ int main(int argc, char **argv)
113 { NULL, 0, NULL, 0} 113 { NULL, 0, NULL, 0}
114 }; 114 };
115 115
116#ifndef WIN32 116#ifndef _WIN32
117 signal(SIGPIPE, SIG_IGN); 117 signal(SIGPIPE, SIG_IGN);
118#endif 118#endif
119 /* parse cmdline args */ 119 /* parse cmdline args */
diff --git a/tools/ideviceenterrecovery.c b/tools/ideviceenterrecovery.c
index 29cc5c9..65eb882 100644
--- a/tools/ideviceenterrecovery.c
+++ b/tools/ideviceenterrecovery.c
@@ -30,7 +30,7 @@
30#include <stdlib.h> 30#include <stdlib.h>
31#include <getopt.h> 31#include <getopt.h>
32#include <errno.h> 32#include <errno.h>
33#ifndef WIN32 33#ifndef _WIN32
34#include <signal.h> 34#include <signal.h>
35#endif 35#endif
36 36
@@ -70,7 +70,7 @@ int main(int argc, char *argv[])
70 { NULL, 0, NULL, 0} 70 { NULL, 0, NULL, 0}
71 }; 71 };
72 72
73#ifndef WIN32 73#ifndef _WIN32
74 signal(SIGPIPE, SIG_IGN); 74 signal(SIGPIPE, SIG_IGN);
75#endif 75#endif
76 /* parse cmdline args */ 76 /* parse cmdline args */
diff --git a/tools/ideviceimagemounter.c b/tools/ideviceimagemounter.c
index 511583e..b319d05 100644
--- a/tools/ideviceimagemounter.c
+++ b/tools/ideviceimagemounter.c
@@ -36,7 +36,8 @@
36#include <time.h> 36#include <time.h>
37#include <sys/time.h> 37#include <sys/time.h>
38#include <inttypes.h> 38#include <inttypes.h>
39#ifndef WIN32 39#include <sys/stat.h>
40#ifndef _WIN32
40#include <signal.h> 41#include <signal.h>
41#endif 42#endif
42 43
@@ -87,7 +88,7 @@ static void print_usage(int argc, char **argv, int is_error)
87 " mount PATH Mount the developer disk image at PATH.\n" 88 " mount PATH Mount the developer disk image at PATH.\n"
88 " For iOS 17+, PATH is a directory containing a .dmg image,\n" 89 " For iOS 17+, PATH is a directory containing a .dmg image,\n"
89 " a BuildManifest.plist, and a Firmware sub-directory;\n" 90 " a BuildManifest.plist, and a Firmware sub-directory;\n"
90 " for older versions PATH is a .dmg filename with a" 91 " for older versions PATH is a .dmg filename with a\n"
91 " .dmg.signature in the same directory, or with another\n" 92 " .dmg.signature in the same directory, or with another\n"
92 " parameter pointing to a file elsewhere.\n" 93 " parameter pointing to a file elsewhere.\n"
93 " list List mounted disk images.\n" 94 " list List mounted disk images.\n"
@@ -183,7 +184,7 @@ int main(int argc, char **argv)
183 size_t image_size = 0; 184 size_t image_size = 0;
184 char *image_sig_path = NULL; 185 char *image_sig_path = NULL;
185 186
186#ifndef WIN32 187#ifndef _WIN32
187 signal(SIGPIPE, SIG_IGN); 188 signal(SIGPIPE, SIG_IGN);
188#endif 189#endif
189 parse_opts(argc, argv); 190 parse_opts(argc, argv);
@@ -267,23 +268,14 @@ int main(int argc, char **argv)
267 goto leave; 268 goto leave;
268 } 269 }
269 270
270 plist_t pver = NULL; 271 unsigned int device_version = idevice_get_device_version(device);
271 char *product_version = NULL; 272
272 lockdownd_get_value(lckd, NULL, "ProductVersion", &pver);
273 if (pver && plist_get_node_type(pver) == PLIST_STRING) {
274 plist_get_string_val(pver, &product_version);
275 }
276 disk_image_upload_type_t disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_AFC; 273 disk_image_upload_type_t disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_AFC;
277 int product_version_major = 0; 274 if (device_version >= IDEVICE_DEVICE_VERSION(7,0,0)) {
278 int product_version_minor = 0; 275 disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE;
279 if (product_version) {
280 if (sscanf(product_version, "%d.%d.%*d", &product_version_major, &product_version_minor) == 2) {
281 if (product_version_major >= 7)
282 disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE;
283 }
284 } 276 }
285 277
286 if (product_version_major >= 16) { 278 if (device_version >= IDEVICE_DEVICE_VERSION(16,0,0)) {
287 uint8_t dev_mode_status = 0; 279 uint8_t dev_mode_status = 0;
288 plist_t val = NULL; 280 plist_t val = NULL;
289 ldret = lockdownd_get_value(lckd, "com.apple.security.mac.amfi", "DeveloperModeStatus", &val); 281 ldret = lockdownd_get_value(lckd, "com.apple.security.mac.amfi", "DeveloperModeStatus", &val);
@@ -336,7 +328,7 @@ int main(int argc, char **argv)
336 goto leave; 328 goto leave;
337 } 329 }
338 image_size = fst.st_size; 330 image_size = fst.st_size;
339 if (product_version_major < 17 && stat(image_sig_path, &fst) != 0) { 331 if (device_version < IDEVICE_DEVICE_VERSION(17,0,0) && stat(image_sig_path, &fst) != 0) {
340 fprintf(stderr, "ERROR: stat: %s: %s\n", image_sig_path, strerror(errno)); 332 fprintf(stderr, "ERROR: stat: %s: %s\n", image_sig_path, strerror(errno));
341 goto leave; 333 goto leave;
342 } 334 }
@@ -351,7 +343,7 @@ int main(int argc, char **argv)
351 if (cmd == CMD_LIST) { 343 if (cmd == CMD_LIST) {
352 /* list mounts mode */ 344 /* list mounts mode */
353 if (!imagetype) { 345 if (!imagetype) {
354 if (product_version_major < 17) { 346 if (device_version < IDEVICE_DEVICE_VERSION(17,0,0)) {
355 imagetype = "Developer"; 347 imagetype = "Developer";
356 } else { 348 } else {
357 imagetype = "Personalized"; 349 imagetype = "Personalized";
@@ -371,7 +363,7 @@ int main(int argc, char **argv)
371 struct stat fst; 363 struct stat fst;
372 plist_t mount_options = NULL; 364 plist_t mount_options = NULL;
373 365
374 if (product_version_major < 17) { 366 if (device_version < IDEVICE_DEVICE_VERSION(17,0,0)) {
375 f = fopen(image_sig_path, "rb"); 367 f = fopen(image_sig_path, "rb");
376 if (!f) { 368 if (!f) {
377 fprintf(stderr, "Error opening signature file '%s': %s\n", image_sig_path, strerror(errno)); 369 fprintf(stderr, "Error opening signature file '%s': %s\n", image_sig_path, strerror(errno));
@@ -606,20 +598,13 @@ int main(int argc, char **argv)
606 case DISK_IMAGE_UPLOAD_TYPE_AFC: 598 case DISK_IMAGE_UPLOAD_TYPE_AFC:
607 default: 599 default:
608 printf("Uploading %s --> afc:///%s\n", image_path, targetname); 600 printf("Uploading %s --> afc:///%s\n", image_path, targetname);
609 char **strs = NULL; 601 plist_t fileinfo = NULL;
610 if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) { 602 if (afc_get_file_info_plist(afc, PKG_PATH, &fileinfo) != AFC_E_SUCCESS) {
611 if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) { 603 if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) {
612 fprintf(stderr, "WARNING: Could not create directory '%s' on device!\n", PKG_PATH); 604 fprintf(stderr, "WARNING: Could not create directory '%s' on device!\n", PKG_PATH);
613 } 605 }
614 } 606 }
615 if (strs) { 607 plist_free(fileinfo);
616 int i = 0;
617 while (strs[i]) {
618 free(strs[i]);
619 i++;
620 }
621 free(strs);
622 }
623 608
624 uint64_t af = 0; 609 uint64_t af = 0;
625 if ((afc_file_open(afc, targetname, AFC_FOPEN_WRONLY, &af) != 610 if ((afc_file_open(afc, targetname, AFC_FOPEN_WRONLY, &af) !=
diff --git a/tools/ideviceinfo.c b/tools/ideviceinfo.c
index fd45763..20cc916 100644
--- a/tools/ideviceinfo.c
+++ b/tools/ideviceinfo.c
@@ -31,7 +31,7 @@
31#include <errno.h> 31#include <errno.h>
32#include <stdlib.h> 32#include <stdlib.h>
33#include <getopt.h> 33#include <getopt.h>
34#ifndef WIN32 34#ifndef _WIN32
35#include <signal.h> 35#include <signal.h>
36#endif 36#endif
37 37
@@ -152,7 +152,7 @@ int main(int argc, char *argv[])
152 { NULL, 0, NULL, 0} 152 { NULL, 0, NULL, 0}
153 }; 153 };
154 154
155#ifndef WIN32 155#ifndef _WIN32
156 signal(SIGPIPE, SIG_IGN); 156 signal(SIGPIPE, SIG_IGN);
157#endif 157#endif
158 158
diff --git a/tools/idevicename.c b/tools/idevicename.c
index 69b76f6..248bda3 100644
--- a/tools/idevicename.c
+++ b/tools/idevicename.c
@@ -30,7 +30,7 @@
30#include <unistd.h> 30#include <unistd.h>
31#include <stdlib.h> 31#include <stdlib.h>
32#include <getopt.h> 32#include <getopt.h>
33#ifndef WIN32 33#ifndef _WIN32
34#include <signal.h> 34#include <signal.h>
35#endif 35#endif
36 36
@@ -72,7 +72,7 @@ int main(int argc, char** argv)
72 const char* udid = NULL; 72 const char* udid = NULL;
73 int use_network = 0; 73 int use_network = 0;
74 74
75#ifndef WIN32 75#ifndef _WIN32
76 signal(SIGPIPE, SIG_IGN); 76 signal(SIGPIPE, SIG_IGN);
77#endif 77#endif
78 78
diff --git a/tools/idevicenotificationproxy.c b/tools/idevicenotificationproxy.c
index d1e25c1..192192a 100644
--- a/tools/idevicenotificationproxy.c
+++ b/tools/idevicenotificationproxy.c
@@ -2,7 +2,8 @@
2 * idevicenotificationproxy.c 2 * idevicenotificationproxy.c
3 * Simple client for the notification_proxy service 3 * Simple client for the notification_proxy service
4 * 4 *
5 * Copyright (c) 2009-2015 Martin Szulecki All Rights Reserved. 5 * Copyright (c) 2018-2024 Nikias Bassen, All Rights Reserved.
6 * Copyright (c) 2009-2015 Martin Szulecki, All Rights Reserved.
6 * 7 *
7 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public 9 * modify it under the terms of the GNU Lesser General Public
@@ -32,7 +33,7 @@
32#include <errno.h> 33#include <errno.h>
33#include <signal.h> 34#include <signal.h>
34 35
35#ifdef WIN32 36#ifdef _WIN32
36#include <windows.h> 37#include <windows.h>
37#define sleep(x) Sleep(x*1000) 38#define sleep(x) Sleep(x*1000)
38#else 39#else
@@ -75,6 +76,7 @@ static void print_usage(int argc, char **argv, int is_error)
75 "\n" 76 "\n"
76 "The following OPTIONS are accepted:\n" 77 "The following OPTIONS are accepted:\n"
77 " -u, --udid UDID target specific device by UDID\n" 78 " -u, --udid UDID target specific device by UDID\n"
79 " -i, --insecure use insecure notification proxy (non-paired device)\n"
78 " -n, --network connect to network device\n" 80 " -n, --network connect to network device\n"
79 " -d, --debug enable communication debugging\n" 81 " -d, --debug enable communication debugging\n"
80 " -h, --help prints usage information\n" 82 " -h, --help prints usage information\n"
@@ -102,6 +104,7 @@ int main(int argc, char *argv[])
102 int i = 0; 104 int i = 0;
103 const char* udid = NULL; 105 const char* udid = NULL;
104 int use_network = 0; 106 int use_network = 0;
107 int insecure = 0;
105 int cmd = CMD_NONE; 108 int cmd = CMD_NONE;
106 char* cmd_arg = NULL; 109 char* cmd_arg = NULL;
107 110
@@ -114,6 +117,7 @@ int main(int argc, char *argv[])
114 { "debug", no_argument, NULL, 'd' }, 117 { "debug", no_argument, NULL, 'd' },
115 { "help", no_argument, NULL, 'h' }, 118 { "help", no_argument, NULL, 'h' },
116 { "udid", required_argument, NULL, 'u' }, 119 { "udid", required_argument, NULL, 'u' },
120 { "insecure", no_argument, NULL, 'i' },
117 { "network", no_argument, NULL, 'n' }, 121 { "network", no_argument, NULL, 'n' },
118 { "version", no_argument, NULL, 'v' }, 122 { "version", no_argument, NULL, 'v' },
119 { NULL, 0, NULL, 0} 123 { NULL, 0, NULL, 0}
@@ -121,13 +125,13 @@ int main(int argc, char *argv[])
121 125
122 signal(SIGINT, clean_exit); 126 signal(SIGINT, clean_exit);
123 signal(SIGTERM, clean_exit); 127 signal(SIGTERM, clean_exit);
124#ifndef WIN32 128#ifndef _WIN32
125 signal(SIGQUIT, clean_exit); 129 signal(SIGQUIT, clean_exit);
126 signal(SIGPIPE, SIG_IGN); 130 signal(SIGPIPE, SIG_IGN);
127#endif 131#endif
128 132
129 /* parse cmdline args */ 133 /* parse cmdline args */
130 while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) { 134 while ((c = getopt_long(argc, argv, "dhu:inv", longopts, NULL)) != -1) {
131 switch (c) { 135 switch (c) {
132 case 'd': 136 case 'd':
133 idevice_set_debug_level(1); 137 idevice_set_debug_level(1);
@@ -143,6 +147,9 @@ int main(int argc, char *argv[])
143 case 'n': 147 case 'n':
144 use_network = 1; 148 use_network = 1;
145 break; 149 break;
150 case 'i':
151 insecure = 1;
152 break;
146 case 'h': 153 case 'h':
147 print_usage(argc, argv, 0); 154 print_usage(argc, argv, 0);
148 return 0; 155 return 0;
@@ -214,12 +221,17 @@ int main(int argc, char *argv[])
214 goto cleanup; 221 goto cleanup;
215 } 222 }
216 223
217 if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) { 224 if (insecure) {
218 fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", ret); 225 ret = lockdownd_client_new(device, &client, TOOL_NAME);
226 } else {
227 ret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME);
228 }
229 if (LOCKDOWN_E_SUCCESS != ret) {
230 fprintf(stderr, "ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(ret), ret);
219 goto cleanup; 231 goto cleanup;
220 } 232 }
221 233
222 ret = lockdownd_start_service(client, NP_SERVICE_NAME, &service); 234 ret = lockdownd_start_service(client, (insecure) ? "com.apple.mobile.insecure_notification_proxy" : NP_SERVICE_NAME, &service);
223 235
224 lockdownd_client_free(client); 236 lockdownd_client_free(client);
225 237
diff --git a/tools/idevicepair.c b/tools/idevicepair.c
index 94d3f04..884c690 100644
--- a/tools/idevicepair.c
+++ b/tools/idevicepair.c
@@ -32,7 +32,7 @@
32#include <getopt.h> 32#include <getopt.h>
33#include <ctype.h> 33#include <ctype.h>
34#include <unistd.h> 34#include <unistd.h>
35#ifdef WIN32 35#ifdef _WIN32
36#include <windows.h> 36#include <windows.h>
37#include <conio.h> 37#include <conio.h>
38#else 38#else
@@ -50,7 +50,7 @@ static char *udid = NULL;
50 50
51#ifdef HAVE_WIRELESS_PAIRING 51#ifdef HAVE_WIRELESS_PAIRING
52 52
53#ifdef WIN32 53#ifdef _WIN32
54#define BS_CC '\b' 54#define BS_CC '\b'
55#define my_getch getch 55#define my_getch getch
56#else 56#else
@@ -293,7 +293,7 @@ int main(int argc, char **argv)
293 } 293 }
294 } 294 }
295 295
296#ifndef WIN32 296#ifndef _WIN32
297 signal(SIGPIPE, SIG_IGN); 297 signal(SIGPIPE, SIG_IGN);
298#endif 298#endif
299 299
diff --git a/tools/ideviceprovision.c b/tools/ideviceprovision.c
index 4080a28..94f4ec5 100644
--- a/tools/ideviceprovision.c
+++ b/tools/ideviceprovision.c
@@ -32,11 +32,12 @@
32#include <getopt.h> 32#include <getopt.h>
33#include <sys/stat.h> 33#include <sys/stat.h>
34#include <errno.h> 34#include <errno.h>
35#ifndef WIN32 35#ifndef _WIN32
36#include <signal.h> 36#include <signal.h>
37#endif 37#endif
38 38
39#ifdef WIN32 39#ifdef _WIN32
40#include <winsock2.h>
40#include <windows.h> 41#include <windows.h>
41#else 42#else
42#include <arpa/inet.h> 43#include <arpa/inet.h>
@@ -314,7 +315,7 @@ int main(int argc, char *argv[])
314 { NULL, 0, NULL, 0} 315 { NULL, 0, NULL, 0}
315 }; 316 };
316 317
317#ifndef WIN32 318#ifndef _WIN32
318 signal(SIGPIPE, SIG_IGN); 319 signal(SIGPIPE, SIG_IGN);
319#endif 320#endif
320 /* parse cmdline args */ 321 /* parse cmdline args */
@@ -475,27 +476,7 @@ int main(int argc, char *argv[])
475 return -1; 476 return -1;
476 } 477 }
477 478
478 plist_t pver = NULL; 479 unsigned int device_version = idevice_get_device_version(device);
479 char *pver_s = NULL;
480 lockdownd_get_value(client, NULL, "ProductVersion", &pver);
481 if (pver && plist_get_node_type(pver) == PLIST_STRING) {
482 plist_get_string_val(pver, &pver_s);
483 }
484 plist_free(pver);
485 int product_version_major = 0;
486 int product_version_minor = 0;
487 int product_version_patch = 0;
488 if (pver_s) {
489 sscanf(pver_s, "%d.%d.%d", &product_version_major, &product_version_minor, &product_version_patch);
490 free(pver_s);
491 }
492 if (product_version_major == 0) {
493 fprintf(stderr, "ERROR: Could not determine the device's ProductVersion\n");
494 lockdownd_client_free(client);
495 idevice_free(device);
496 return -1;
497 }
498 int product_version = ((product_version_major & 0xFF) << 16) | ((product_version_minor & 0xFF) << 8) | (product_version_patch & 0xFF);
499 480
500 lockdownd_error_t lerr = lockdownd_start_service(client, MISAGENT_SERVICE_NAME, &service); 481 lockdownd_error_t lerr = lockdownd_start_service(client, MISAGENT_SERVICE_NAME, &service);
501 if (lerr != LOCKDOWN_E_SUCCESS) { 482 if (lerr != LOCKDOWN_E_SUCCESS) {
@@ -546,7 +527,7 @@ int main(int argc, char *argv[])
546 { 527 {
547 plist_t profiles = NULL; 528 plist_t profiles = NULL;
548 misagent_error_t merr; 529 misagent_error_t merr;
549 if (product_version < 0x090300) { 530 if (device_version < IDEVICE_DEVICE_VERSION(9,3,0)) {
550 merr = misagent_copy(mis, &profiles); 531 merr = misagent_copy(mis, &profiles);
551 } else { 532 } else {
552 merr = misagent_copy_all(mis, &profiles); 533 merr = misagent_copy_all(mis, &profiles);
@@ -631,7 +612,7 @@ int main(int argc, char *argv[])
631 /* remove all provisioning profiles */ 612 /* remove all provisioning profiles */
632 plist_t profiles = NULL; 613 plist_t profiles = NULL;
633 misagent_error_t merr; 614 misagent_error_t merr;
634 if (product_version < 0x090300) { 615 if (device_version < IDEVICE_DEVICE_VERSION(9,3,0)) {
635 merr = misagent_copy(mis, &profiles); 616 merr = misagent_copy(mis, &profiles);
636 } else { 617 } else {
637 merr = misagent_copy_all(mis, &profiles); 618 merr = misagent_copy_all(mis, &profiles);
diff --git a/tools/idevicescreenshot.c b/tools/idevicescreenshot.c
index 0e694c7..bfaa059 100644
--- a/tools/idevicescreenshot.c
+++ b/tools/idevicescreenshot.c
@@ -32,7 +32,7 @@
32#include <errno.h> 32#include <errno.h>
33#include <time.h> 33#include <time.h>
34#include <unistd.h> 34#include <unistd.h>
35#ifndef WIN32 35#ifndef _WIN32
36#include <signal.h> 36#include <signal.h>
37#endif 37#endif
38 38
@@ -142,7 +142,7 @@ int main(int argc, char **argv)
142 { NULL, 0, NULL, 0} 142 { NULL, 0, NULL, 0}
143 }; 143 };
144 144
145#ifndef WIN32 145#ifndef _WIN32
146 signal(SIGPIPE, SIG_IGN); 146 signal(SIGPIPE, SIG_IGN);
147#endif 147#endif
148 /* parse cmdline args */ 148 /* parse cmdline args */
diff --git a/tools/idevicesetlocation.c b/tools/idevicesetlocation.c
index 69fbaf5..dca8830 100644
--- a/tools/idevicesetlocation.c
+++ b/tools/idevicesetlocation.c
@@ -113,7 +113,7 @@ int main(int argc, char **argv)
113 113
114 if ((argc > 2) || (argc < 1)) { 114 if ((argc > 2) || (argc < 1)) {
115 print_usage(argc+optind, argv-optind, 1); 115 print_usage(argc+optind, argv-optind, 1);
116 return -1; 116 return 1;
117 } 117 }
118 118
119 if (argc == 2) { 119 if (argc == 2) {
@@ -123,7 +123,7 @@ int main(int argc, char **argv)
123 mode = RESET_LOCATION; 123 mode = RESET_LOCATION;
124 } else { 124 } else {
125 print_usage(argc+optind, argv-optind, 1); 125 print_usage(argc+optind, argv-optind, 1);
126 return -1; 126 return 1;
127 } 127 }
128 } 128 }
129 129
@@ -135,19 +135,30 @@ int main(int argc, char **argv)
135 } else { 135 } else {
136 printf("ERROR: No device found!\n"); 136 printf("ERROR: No device found!\n");
137 } 137 }
138 return -1; 138 return 1;
139 } 139 }
140 140
141 lockdownd_client_t lockdown; 141 lockdownd_client_t lockdown = NULL;
142 lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME); 142 lockdownd_error_t lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME);
143 if (lerr != LOCKDOWN_E_SUCCESS) {
144 idevice_free(device);
145 printf("ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(lerr), lerr);
146 return 1;
147 }
143 148
144 lockdownd_service_descriptor_t svc = NULL; 149 lockdownd_service_descriptor_t svc = NULL;
145 lockdownd_error_t lerr = lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE, &svc); 150 lerr = lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE, &svc);
146 if (lerr != LOCKDOWN_E_SUCCESS) { 151 if (lerr != LOCKDOWN_E_SUCCESS) {
152 unsigned int device_version = idevice_get_device_version(device);
147 lockdownd_client_free(lockdown); 153 lockdownd_client_free(lockdown);
148 idevice_free(device); 154 idevice_free(device);
149 printf("ERROR: Could not start the simulatelocation service: %s\nMake sure a developer disk image is mounted!\n", lockdownd_strerror(lerr)); 155 printf("ERROR: Could not start the simulatelocation service: %s\n", lockdownd_strerror(lerr));
150 return -1; 156 if (device_version >= IDEVICE_DEVICE_VERSION(17,0,0)) {
157 printf("Note: This tool is currently not supported on iOS 17+\n");
158 } else {
159 printf("Make sure a developer disk image is mounted!\n");
160 }
161 return 1;
151 } 162 }
152 lockdownd_client_free(lockdown); 163 lockdownd_client_free(lockdown);
153 164
@@ -158,10 +169,9 @@ int main(int argc, char **argv)
158 lockdownd_service_descriptor_free(svc); 169 lockdownd_service_descriptor_free(svc);
159 170
160 if (serr != SERVICE_E_SUCCESS) { 171 if (serr != SERVICE_E_SUCCESS) {
161 lockdownd_client_free(lockdown);
162 idevice_free(device); 172 idevice_free(device);
163 printf("ERROR: Could not connect to simulatelocation service (%d)\n", serr); 173 printf("ERROR: Could not connect to simulatelocation service (%d)\n", serr);
164 return -1; 174 return 1;
165 } 175 }
166 176
167 uint32_t l; 177 uint32_t l;
diff --git a/tools/idevicesyslog.c b/tools/idevicesyslog.c
index a0e641d..88af4c1 100644
--- a/tools/idevicesyslog.c
+++ b/tools/idevicesyslog.c
@@ -33,8 +33,9 @@
33#include <stdlib.h> 33#include <stdlib.h>
34#include <unistd.h> 34#include <unistd.h>
35#include <getopt.h> 35#include <getopt.h>
36#include <time.h>
36 37
37#ifdef WIN32 38#ifdef _WIN32
38#include <windows.h> 39#include <windows.h>
39#define sleep(x) Sleep(x*1000) 40#define sleep(x) Sleep(x*1000)
40#endif 41#endif
@@ -42,10 +43,12 @@
42#include <libimobiledevice/libimobiledevice.h> 43#include <libimobiledevice/libimobiledevice.h>
43#include <libimobiledevice/syslog_relay.h> 44#include <libimobiledevice/syslog_relay.h>
44#include <libimobiledevice-glue/termcolors.h> 45#include <libimobiledevice-glue/termcolors.h>
46#include <libimobiledevice/ostrace.h>
45 47
46static int quit_flag = 0; 48static int quit_flag = 0;
47static int exit_on_disconnect = 0; 49static int exit_on_disconnect = 0;
48static int show_device_name = 0; 50static int show_device_name = 0;
51static int force_syslog_relay = 0;
49 52
50static char* udid = NULL; 53static char* udid = NULL;
51static char** proc_filters = NULL; 54static char** proc_filters = NULL;
@@ -58,6 +61,9 @@ static int num_pid_filters = 0;
58static char** msg_filters = NULL; 61static char** msg_filters = NULL;
59static int num_msg_filters = 0; 62static int num_msg_filters = 0;
60 63
64static char** msg_reverse_filters = NULL;
65static int num_msg_reverse_filters = 0;
66
61static char** trigger_filters = NULL; 67static char** trigger_filters = NULL;
62static int num_trigger_filters = 0; 68static int num_trigger_filters = 0;
63static char** untrigger_filters = NULL; 69static char** untrigger_filters = NULL;
@@ -66,11 +72,16 @@ static int triggered = 0;
66 72
67static idevice_t device = NULL; 73static idevice_t device = NULL;
68static syslog_relay_client_t syslog = NULL; 74static syslog_relay_client_t syslog = NULL;
75static ostrace_client_t ostrace = NULL;
69 76
70static const char QUIET_FILTER[] = "CircleJoinRequested|CommCenter|HeuristicInterpreter|MobileMail|PowerUIAgent|ProtectedCloudKeySyncing|SpringBoard|UserEventAgent|WirelessRadioManagerd|accessoryd|accountsd|aggregated|analyticsd|appstored|apsd|assetsd|assistant_service|backboardd|biometrickitd|bluetoothd|calaccessd|callservicesd|cloudd|com.apple.Safari.SafeBrowsing.Service|contextstored|corecaptured|coreduetd|corespeechd|cdpd|dasd|dataaccessd|distnoted|dprivacyd|duetexpertd|findmydeviced|fmfd|fmflocatord|gpsd|healthd|homed|identityservicesd|imagent|itunescloudd|itunesstored|kernel|locationd|maild|mDNSResponder|mediaremoted|mediaserverd|mobileassetd|nanoregistryd|nanotimekitcompaniond|navd|nsurlsessiond|passd|pasted|photoanalysisd|powerd|powerlogHelperd|ptpd|rapportd|remindd|routined|runningboardd|searchd|sharingd|suggestd|symptomsd|timed|thermalmonitord|useractivityd|vmd|wifid|wirelessproxd"; 77static const char QUIET_FILTER[] = "CircleJoinRequested|CommCenter|HeuristicInterpreter|MobileMail|PowerUIAgent|ProtectedCloudKeySyncing|SpringBoard|UserEventAgent|WirelessRadioManagerd|accessoryd|accountsd|aggregated|analyticsd|appstored|apsd|assetsd|assistant_service|backboardd|biometrickitd|bluetoothd|calaccessd|callservicesd|cloudd|com.apple.Safari.SafeBrowsing.Service|contextstored|corecaptured|coreduetd|corespeechd|cdpd|dasd|dataaccessd|distnoted|dprivacyd|duetexpertd|findmydeviced|fmfd|fmflocatord|gpsd|healthd|homed|identityservicesd|imagent|itunescloudd|itunesstored|kernel|locationd|maild|mDNSResponder|mediaremoted|mediaserverd|mobileassetd|nanoregistryd|nanotimekitcompaniond|navd|nsurlsessiond|passd|pasted|photoanalysisd|powerd|powerlogHelperd|ptpd|rapportd|remindd|routined|runningboardd|searchd|sharingd|suggestd|symptomsd|timed|thermalmonitord|useractivityd|vmd|wifid|wirelessproxd";
71 78
72static int use_network = 0; 79static int use_network = 0;
73 80
81static long long start_time = -1;
82static long long size_limit = -1;
83static long long age_limit = -1;
84
74static char *line = NULL; 85static char *line = NULL;
75static int line_buffer_size = 0; 86static int line_buffer_size = 0;
76static int lp = 0; 87static int lp = 0;
@@ -129,6 +140,70 @@ static int find_char(char c, char** p, const char* end)
129 140
130static void stop_logging(void); 141static void stop_logging(void);
131 142
143static int message_filter_matching(const char* message)
144{
145 if (num_msg_filters > 0) {
146 int found = 0;
147 int i;
148 for (i = 0; i < num_msg_filters; i++) {
149 if (strstr(message, msg_filters[i])) {
150 found = 1;
151 break;
152 }
153 }
154 if (!found) {
155 return 0;
156 }
157 }
158 if (num_msg_reverse_filters > 0) {
159 int found = 0;
160 int i;
161 for (i = 0; i < num_msg_reverse_filters; i++) {
162 if (strstr(message, msg_reverse_filters[i])) {
163 found = 1;
164 break;
165 }
166 }
167 if (found) {
168 return 0;
169 }
170 }
171 return 1;
172}
173
174static int process_filter_matching(int pid, const char* process_name, int process_name_length)
175{
176 int proc_matched = 0;
177 if (num_pid_filters > 0) {
178 int found = proc_filter_excluding;
179 int i = 0;
180 for (i = 0; i < num_pid_filters; i++) {
181 if (pid == pid_filters[i]) {
182 found = !proc_filter_excluding;
183 break;
184 }
185 }
186 if (found) {
187 proc_matched = 1;
188 }
189 }
190 if (num_proc_filters > 0 && !proc_matched) {
191 int found = proc_filter_excluding;
192 int i = 0;
193 for (i = 0; i < num_proc_filters; i++) {
194 if (!proc_filters[i]) continue;
195 if (strncmp(proc_filters[i], process_name, process_name_length) == 0) {
196 found = !proc_filter_excluding;
197 break;
198 }
199 }
200 if (found) {
201 proc_matched = 1;
202 }
203 }
204 return proc_matched;
205}
206
132static void syslog_callback(char c, void *user_data) 207static void syslog_callback(char c, void *user_data)
133{ 208{
134 if (lp >= line_buffer_size-1) { 209 if (lp >= line_buffer_size-1) {
@@ -202,20 +277,9 @@ static void syslog_callback(char c, void *user_data)
202 } 277 }
203 278
204 /* check message filters */ 279 /* check message filters */
205 if (num_msg_filters > 0) { 280 shall_print = message_filter_matching(device_name_end+1);
206 int found = 0; 281 if (!shall_print) {
207 int i; 282 break;
208 for (i = 0; i < num_msg_filters; i++) {
209 if (strstr(device_name_end+1, msg_filters[i])) {
210 found = 1;
211 break;
212 }
213 }
214 if (!found) {
215 shall_print = 0;
216 break;
217 }
218 shall_print = 1;
219 } 283 }
220 284
221 /* process name */ 285 /* process name */
@@ -235,39 +299,10 @@ static void syslog_callback(char c, void *user_data)
235 proc_name_end = p; 299 proc_name_end = p;
236 p++; 300 p++;
237 301
238 int proc_matched = 0; 302 /* match pid / process name */
239 if (num_pid_filters > 0) { 303 char* endp = NULL;
240 char* endp = NULL; 304 int pid_value = (int)strtol(pid_start, &endp, 10);
241 int pid_value = (int)strtol(pid_start, &endp, 10); 305 if (process_filter_matching(pid_value, process_name_start, process_name_end-process_name_start)) {
242 if (endp && (*endp == ']')) {
243 int found = proc_filter_excluding;
244 int i = 0;
245 for (i = 0; i < num_pid_filters; i++) {
246 if (pid_value == pid_filters[i]) {
247 found = !proc_filter_excluding;
248 break;
249 }
250 }
251 if (found) {
252 proc_matched = 1;
253 }
254 }
255 }
256 if (num_proc_filters > 0 && !proc_matched) {
257 int found = proc_filter_excluding;
258 int i = 0;
259 for (i = 0; i < num_proc_filters; i++) {
260 if (!proc_filters[i]) continue;
261 if (strncmp(proc_filters[i], process_name_start, process_name_end-process_name_start) == 0) {
262 found = !proc_filter_excluding;
263 break;
264 }
265 }
266 if (found) {
267 proc_matched = 1;
268 }
269 }
270 if (proc_matched) {
271 shall_print = 1; 306 shall_print = 1;
272 } else { 307 } else {
273 if (num_pid_filters > 0 || num_proc_filters > 0) { 308 if (num_pid_filters > 0 || num_proc_filters > 0) {
@@ -331,7 +366,7 @@ static void syslog_callback(char c, void *user_data)
331 } 366 }
332 } while (0); 367 } while (0);
333 368
334 if ((num_msg_filters == 0 && num_proc_filters == 0 && num_pid_filters == 0 && num_trigger_filters == 0 && num_untrigger_filters == 0) || shall_print) { 369 if ((num_msg_filters == 0 && num_msg_reverse_filters == 0 && num_proc_filters == 0 && num_pid_filters == 0 && num_trigger_filters == 0 && num_untrigger_filters == 0) || shall_print) {
335 fwrite(linep, 1, lp, stdout); 370 fwrite(linep, 1, lp, stdout);
336 cprintf(COLOR_RESET); 371 cprintf(COLOR_RESET);
337 fflush(stdout); 372 fflush(stdout);
@@ -345,12 +380,231 @@ static void syslog_callback(char c, void *user_data)
345 } 380 }
346} 381}
347 382
348static int start_logging(void) 383static void ostrace_syslog_callback(const void* buf, size_t len, void* user_data)
349{ 384{
350 idevice_error_t ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); 385 if (len < 0x81) {
351 if (ret != IDEVICE_E_SUCCESS) { 386 fprintf(stderr, "Error: not enough data in callback function?!\n");
352 fprintf(stderr, "Device with udid %s not found!?\n", udid); 387 return;
353 return -1; 388 }
389
390 struct ostrace_packet_header_t *trace_hdr = (struct ostrace_packet_header_t*)buf;
391
392 if (trace_hdr->marker != 2 || (trace_hdr->type != 8 && trace_hdr->type != 2)) {
393 fprintf(stderr, "unexpected packet data %02x %08x\n", trace_hdr->marker, trace_hdr->type);
394 }
395
396 const char* dataptr = (const char*)buf + trace_hdr->header_size;
397 const char* process_name = dataptr;
398 const char* image_name = (trace_hdr->imagepath_len > 0) ? dataptr + trace_hdr->procpath_len : NULL;
399 const char* message = (trace_hdr->message_len > 0) ? dataptr + trace_hdr->procpath_len + trace_hdr->imagepath_len : NULL;
400 //const char* subsystem = (trace_hdr->subsystem_len > 0) ? dataptr + trace_hdr->procpath_len + trace_hdr->imagepath_len + trace_hdr->message_len : NULL;
401 //const char* category = (trace_hdr->category_len > 0) ? dataptr + trace_hdr->procpath_len + trace_hdr->imagepath_len + trace_hdr->message_len + trace_hdr->subsystem_len : NULL;
402
403 int shall_print = 1;
404 int trigger_off = 0;
405 const char* process_name_short = (process_name) ? strrchr(process_name, '/') : "";
406 process_name_short = (process_name_short) ? process_name_short+1 : process_name;
407 const char* image_name_short = (image_name) ? strrchr(image_name, '/') : NULL;
408 image_name_short = (image_name_short) ? image_name_short+1 : process_name;
409 if (image_name_short && !strcmp(image_name_short, process_name_short)) {
410 image_name_short = NULL;
411 }
412
413 do {
414 /* check if we have any triggers/untriggers */
415 if (num_untrigger_filters > 0 && triggered) {
416 int found = 0;
417 int i;
418 for (i = 0; i < num_untrigger_filters; i++) {
419 if (strstr(message, untrigger_filters[i])) {
420 found = 1;
421 break;
422 }
423 }
424 if (!found) {
425 shall_print = 1;
426 } else {
427 shall_print = 1;
428 trigger_off = 1;
429 }
430 } else if (num_trigger_filters > 0 && !triggered) {
431 int found = 0;
432 int i;
433 for (i = 0; i < num_trigger_filters; i++) {
434 if (strstr(message, trigger_filters[i])) {
435 found = 1;
436 break;
437 }
438 }
439 if (!found) {
440 shall_print = 0;
441 break;
442 }
443 triggered = 1;
444 shall_print = 1;
445 } else if (num_trigger_filters == 0 && num_untrigger_filters > 0 && !triggered) {
446 shall_print = 0;
447 quit_flag++;
448 break;
449 }
450
451 /* check message filters */
452 shall_print = message_filter_matching(message);
453 if (!shall_print) {
454 break;
455 }
456
457 /* check process filters */
458 if (process_filter_matching(trace_hdr->pid, process_name_short, strlen(process_name_short))) {
459 shall_print = 1;
460 } else {
461 if (num_pid_filters > 0 || num_proc_filters > 0) {
462 shall_print = 0;
463 }
464 }
465 if (!shall_print) {
466 break;
467 }
468 } while (0);
469
470 if (!shall_print) {
471 return;
472 }
473
474 const char* level_str = "Unknown";
475 const char* level_color = FG_YELLOW;
476 switch (trace_hdr->level) {
477 case 0:
478 level_str = "Notice";
479 level_color = FG_GREEN;
480 break;
481 case 0x01:
482 level_str = "Info";
483 level_color = FG_WHITE;
484 break;
485 case 0x02:
486 level_str = "Debug";
487 level_color = FG_MAGENTA;
488 break;
489 case 0x10:
490 level_str = "Error";
491 level_color = FG_RED;
492 break;
493 case 0x11:
494 level_str = "Fault";
495 level_color = FG_RED;
496 default:
497 break;
498 }
499
500 char datebuf[24];
501 struct tm *tp;
502 time_t time_sec = (time_t)trace_hdr->time_sec;
503#ifdef HAVE_LOCALTIME_R
504 struct tm tp_ = {0, };
505 tp = localtime_r(&time_sec, &tp_);
506#else
507 tp = localtime(&time_sec);
508#endif
509#ifdef _WIN32
510 strftime(datebuf, 16, "%b %#d %H:%M:%S", tp);
511#else
512 strftime(datebuf, 16, "%b %e %H:%M:%S", tp);
513#endif
514 snprintf(datebuf+15, 9, ".%06u", trace_hdr->time_usec);
515
516 /* write date and time */
517 cprintf(FG_LIGHT_GRAY "%s ", datebuf);
518
519 if (show_device_name) {
520 /* write device name TODO do we need this? */
521 //cprintf(FG_DARK_YELLOW "%s ", device_name);
522 }
523
524 /* write process name */
525 cprintf(FG_BRIGHT_CYAN "%s" FG_CYAN, process_name_short);
526 if (image_name_short) {
527 cprintf("(%s)", image_name_short);
528 }
529 cprintf("[%d]" COLOR_RESET " ", trace_hdr->pid);
530
531 /* write log level */
532 cprintf(level_color);
533 cprintf("<%s>:" COLOR_RESET " ", level_str);
534
535 /* write message */
536 cprintf(FG_WHITE);
537 cprintf("%s" COLOR_RESET "\n", message);
538 fflush(stdout);
539
540 if (trigger_off) {
541 triggered = 0;
542 }
543}
544
545static plist_t get_pid_list()
546{
547 plist_t list = NULL;
548 ostrace_client_t ostrace_tmp = NULL;
549 ostrace_client_start_service(device, &ostrace_tmp, TOOL_NAME);
550 if (ostrace_tmp) {
551 ostrace_get_pid_list(ostrace_tmp, &list);
552 ostrace_client_free(ostrace_tmp);
553 }
554 return list;
555}
556
557static int pid_valid(int pid)
558{
559 plist_t list = get_pid_list();
560 if (!list) return 0;
561 char valbuf[16];
562 snprintf(valbuf, 16, "%d", pid);
563 return (plist_dict_get_item(list, valbuf)) ? 1 : 0;
564}
565
566static int pid_for_proc(const char* procname)
567{
568 int result = -1;
569 plist_t list = get_pid_list();
570 if (!list) {
571 return result;
572 }
573 plist_dict_iter iter = NULL;
574 plist_dict_new_iter(list, &iter);
575 if (iter) {
576 plist_t node = NULL;
577 do {
578 char* key = NULL;
579 node = NULL;
580 plist_dict_next_item(list, iter, &key, &node);
581 if (!key) {
582 break;
583 }
584 if (PLIST_IS_DICT(node)) {
585 plist_t pname = plist_dict_get_item(node, "ProcessName");
586 if (PLIST_IS_STRING(pname)) {
587 if (!strcmp(plist_get_string_ptr(pname, NULL), procname)) {
588 result = (int)strtol(key, NULL, 10);
589 }
590 }
591 }
592 free(key);
593 } while (node);
594 plist_mem_free(iter);
595 }
596 plist_free(list);
597 return result;
598}
599
600static int connect_service(int ostrace_required)
601{
602 if (!device) {
603 idevice_error_t ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
604 if (ret != IDEVICE_E_SUCCESS) {
605 fprintf(stderr, "Device with udid %s not found!?\n", udid);
606 return -1;
607 }
354 } 608 }
355 609
356 lockdownd_client_t lockdown = NULL; 610 lockdownd_client_t lockdown = NULL;
@@ -361,14 +615,28 @@ static int start_logging(void)
361 device = NULL; 615 device = NULL;
362 return -1; 616 return -1;
363 } 617 }
364
365 /* start syslog_relay service */
366 lockdownd_service_descriptor_t svc = NULL; 618 lockdownd_service_descriptor_t svc = NULL;
367 lerr = lockdownd_start_service(lockdown, SYSLOG_RELAY_SERVICE_NAME, &svc); 619
620 const char* service_name = OSTRACE_SERVICE_NAME;
621 int use_ostrace = 1;
622 if (idevice_get_device_version(device) < IDEVICE_DEVICE_VERSION(9,0,0) || force_syslog_relay) {
623 service_name = SYSLOG_RELAY_SERVICE_NAME;
624 use_ostrace = 0;
625 }
626 if (ostrace_required && !use_ostrace) {
627 fprintf(stderr, "ERROR: This operation requires iOS 9 or later.\n");
628 lockdownd_client_free(lockdown);
629 idevice_free(device);
630 device = NULL;
631 return -1;
632 }
633
634 /* start syslog_relay/os_trace_relay service */
635 lerr = lockdownd_start_service(lockdown, service_name, &svc);
368 if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { 636 if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) {
369 fprintf(stderr, "*** Device is passcode protected, enter passcode on the device to continue ***\n"); 637 fprintf(stderr, "*** Device is passcode protected, enter passcode on the device to continue ***\n");
370 while (!quit_flag) { 638 while (!quit_flag) {
371 lerr = lockdownd_start_service(lockdown, SYSLOG_RELAY_SERVICE_NAME, &svc); 639 lerr = lockdownd_start_service(lockdown, service_name, &svc);
372 if (lerr != LOCKDOWN_E_PASSWORD_PROTECTED) { 640 if (lerr != LOCKDOWN_E_PASSWORD_PROTECTED) {
373 break; 641 break;
374 } 642 }
@@ -376,32 +644,84 @@ static int start_logging(void)
376 } 644 }
377 } 645 }
378 if (lerr != LOCKDOWN_E_SUCCESS) { 646 if (lerr != LOCKDOWN_E_SUCCESS) {
379 fprintf(stderr, "ERROR: Could not connect to lockdownd: %d\n", lerr); 647 fprintf(stderr, "ERROR: Could not start %s service: %s (%d)\n", service_name, lockdownd_strerror(lerr), lerr);
380 idevice_free(device); 648 idevice_free(device);
381 device = NULL; 649 device = NULL;
382 return -1; 650 return -1;
383 } 651 }
384 lockdownd_client_free(lockdown); 652 lockdownd_client_free(lockdown);
385 653
386 /* connect to syslog_relay service */ 654 if (use_ostrace) {
387 syslog_relay_error_t serr = SYSLOG_RELAY_E_UNKNOWN_ERROR; 655 /* connect to os_trace_relay service */
388 serr = syslog_relay_client_new(device, svc, &syslog); 656 ostrace_error_t serr = OSTRACE_E_UNKNOWN_ERROR;
389 lockdownd_service_descriptor_free(svc); 657 serr = ostrace_client_new(device, svc, &ostrace);
390 if (serr != SYSLOG_RELAY_E_SUCCESS) { 658 lockdownd_service_descriptor_free(svc);
391 fprintf(stderr, "ERROR: Could not start service com.apple.syslog_relay.\n"); 659 if (serr != OSTRACE_E_SUCCESS) {
392 idevice_free(device); 660 fprintf(stderr, "ERROR: Could not connect to %s service (%d)\n", service_name, serr);
393 device = NULL; 661 idevice_free(device);
662 device = NULL;
663 return -1;
664 }
665 } else {
666 /* connect to syslog_relay service */
667 syslog_relay_error_t serr = SYSLOG_RELAY_E_UNKNOWN_ERROR;
668 serr = syslog_relay_client_new(device, svc, &syslog);
669 lockdownd_service_descriptor_free(svc);
670 if (serr != SYSLOG_RELAY_E_SUCCESS) {
671 fprintf(stderr, "ERROR: Could not connect to %s service (%d)\n", service_name, serr);
672 idevice_free(device);
673 device = NULL;
674 return -1;
675 }
676 }
677 return 0;
678}
679
680static int start_logging(void)
681{
682 if (connect_service(0) < 0) {
394 return -1; 683 return -1;
395 } 684 }
396 685
397 /* start capturing syslog */ 686 /* start capturing syslog */
398 serr = syslog_relay_start_capture_raw(syslog, syslog_callback, NULL); 687 if (ostrace) {
399 if (serr != SYSLOG_RELAY_E_SUCCESS) { 688 plist_t options = plist_new_dict();
400 fprintf(stderr, "ERROR: Unable tot start capturing syslog.\n"); 689 if (num_proc_filters == 0 && num_pid_filters == 1 && !proc_filter_excluding) {
401 syslog_relay_client_free(syslog); 690 if (pid_filters[0] > 0) {
402 syslog = NULL; 691 if (!pid_valid(pid_filters[0])) {
403 idevice_free(device); 692 fprintf(stderr, "NOTE: A process with pid doesn't exists!\n");
404 device = NULL; 693 }
694 }
695 plist_dict_set_item(options, "Pid", plist_new_int(pid_filters[0]));
696 } else if (num_proc_filters == 1 && num_pid_filters == 0 && !proc_filter_excluding) {
697 int pid = pid_for_proc(proc_filters[0]);
698 if (!strcmp(proc_filters[0], "kernel")) {
699 pid = 0;
700 }
701 if (pid >= 0) {
702 plist_dict_set_item(options, "Pid", plist_new_int(pid));
703 }
704 }
705 ostrace_error_t serr = ostrace_start_activity(ostrace, options, ostrace_syslog_callback, NULL);
706 if (serr != OSTRACE_E_SUCCESS) {
707 fprintf(stderr, "ERROR: Unable to start capturing syslog.\n");
708 ostrace_client_free(ostrace);
709 ostrace = NULL;
710 idevice_free(device);
711 device = NULL;
712 return -1;
713 }
714 } else if (syslog) {
715 syslog_relay_error_t serr = syslog_relay_start_capture_raw(syslog, syslog_callback, NULL);
716 if (serr != SYSLOG_RELAY_E_SUCCESS) {
717 fprintf(stderr, "ERROR: Unable to start capturing syslog.\n");
718 syslog_relay_client_free(syslog);
719 syslog = NULL;
720 idevice_free(device);
721 device = NULL;
722 return -1;
723 }
724 } else {
405 return -1; 725 return -1;
406 } 726 }
407 727
@@ -419,6 +739,11 @@ static void stop_logging(void)
419 syslog_relay_client_free(syslog); 739 syslog_relay_client_free(syslog);
420 syslog = NULL; 740 syslog = NULL;
421 } 741 }
742 if (ostrace) {
743 ostrace_stop_activity(ostrace);
744 ostrace_client_free(ostrace);
745 ostrace = NULL;
746 }
422 747
423 if (device) { 748 if (device) {
424 idevice_free(device); 749 idevice_free(device);
@@ -426,6 +751,77 @@ static void stop_logging(void)
426 } 751 }
427} 752}
428 753
754static int write_callback(const void* buf, size_t len, void *user_data)
755{
756 FILE* f = (FILE*)user_data;
757 ssize_t res = fwrite(buf, 1, len, f);
758 if (res < 0) {
759 return -1;
760 }
761 if (quit_flag > 0) {
762 return -1;
763 }
764 return 0;
765}
766
767static void print_sorted_pidlist(plist_t list)
768{
769 struct listelem;
770 struct listelem {
771 int val;
772 struct listelem *next;
773 };
774 struct listelem* sortedlist = NULL;
775
776 plist_dict_iter iter = NULL;
777 plist_dict_new_iter(list, &iter);
778 if (iter) {
779 plist_t node = NULL;
780 do {
781 char* key = NULL;
782 node = NULL;
783 plist_dict_next_item(list, iter, &key, &node);
784 if (key) {
785 int pidval = (int)strtol(key, NULL, 10);
786 struct listelem* elem = (struct listelem*)malloc(sizeof(struct listelem));
787 elem->val = pidval;
788 elem->next = NULL;
789 struct listelem* prev = NULL;
790 struct listelem* curr = sortedlist;
791
792 while (curr && pidval > curr->val) {
793 prev = curr;
794 curr = curr->next;
795 }
796
797 elem->next = curr;
798 if (prev == NULL) {
799 sortedlist = elem;
800 } else {
801 prev->next = elem;
802 }
803 free(key);
804 }
805 } while (node);
806 plist_mem_free(iter);
807 }
808 struct listelem *listp = sortedlist;
809 char pidstr[16];
810 while (listp) {
811 snprintf(pidstr, 16, "%d", listp->val);
812 plist_t node = plist_dict_get_item(list, pidstr);
813 if (PLIST_IS_DICT(node)) {
814 plist_t pname = plist_dict_get_item(node, "ProcessName");
815 if (PLIST_IS_STRING(pname)) {
816 printf("%d %s\n", listp->val, plist_get_string_ptr(pname, NULL));
817 }
818 }
819 struct listelem *curr = listp;
820 listp = listp->next;
821 free(curr);
822 }
823}
824
429static void device_event_cb(const idevice_event_t* event, void* userdata) 825static void device_event_cb(const idevice_event_t* event, void* userdata)
430{ 826{
431 if (use_network && event->conn_type != CONNECTION_NETWORK) { 827 if (use_network && event->conn_type != CONNECTION_NETWORK) {
@@ -435,7 +831,7 @@ static void device_event_cb(const idevice_event_t* event, void* userdata)
435 return; 831 return;
436 } 832 }
437 if (event->event == IDEVICE_DEVICE_ADD) { 833 if (event->event == IDEVICE_DEVICE_ADD) {
438 if (!syslog) { 834 if (!syslog && !ostrace) {
439 if (!udid) { 835 if (!udid) {
440 udid = strdup(event->udid); 836 udid = strdup(event->udid);
441 } 837 }
@@ -446,7 +842,7 @@ static void device_event_cb(const idevice_event_t* event, void* userdata)
446 } 842 }
447 } 843 }
448 } else if (event->event == IDEVICE_DEVICE_REMOVE) { 844 } else if (event->event == IDEVICE_DEVICE_REMOVE) {
449 if (syslog && (strcmp(udid, event->udid) == 0)) { 845 if ((syslog || ostrace) && (strcmp(udid, event->udid) == 0)) {
450 stop_logging(); 846 stop_logging();
451 fprintf(stdout, "[disconnected:%s]\n", udid); 847 fprintf(stdout, "[disconnected:%s]\n", udid);
452 if (exit_on_disconnect) { 848 if (exit_on_disconnect) {
@@ -484,9 +880,20 @@ static void print_usage(int argc, char **argv, int is_error)
484 " -o, --output FILE write to FILE instead of stdout\n" 880 " -o, --output FILE write to FILE instead of stdout\n"
485 " (existing FILE will be overwritten)\n" 881 " (existing FILE will be overwritten)\n"
486 " --colors force writing colored output, e.g. for --output\n" 882 " --colors force writing colored output, e.g. for --output\n"
883 " --syslog-relay force use of syslog_relay service\n"
884 "\n"
885 "COMMANDS:\n"
886 " pidlist Print pid and name of all running processes.\n"
887 " archive PATH Request a logarchive and write it to PATH.\n"
888 " Output can be piped to another process using - as PATH.\n"
889 " The file data will be in .tar format.\n"
890 " --start-time VALUE start time of the log data as UNIX timestamp\n"
891 " --age-limit VALUE maximum age of the log data\n"
892 " --size-limit VALUE limit the size of the archive\n"
487 "\n" 893 "\n"
488 "FILTER OPTIONS:\n" 894 "FILTER OPTIONS:\n"
489 " -m, --match STRING only print messages that contain STRING\n" 895 " -m, --match STRING only print messages that contain STRING\n"
896 " -M, --unmatch STRING print messages that not contain STRING\n"
490 " -t, --trigger STRING start logging when matching STRING\n" 897 " -t, --trigger STRING start logging when matching STRING\n"
491 " -T, --untrigger STRING stop logging when matching STRING\n" 898 " -T, --untrigger STRING stop logging when matching STRING\n"
492 " -p, --process PROCESS only print messages from matching process(es)\n" 899 " -p, --process PROCESS only print messages from matching process(es)\n"
@@ -530,6 +937,12 @@ int main(int argc, char *argv[])
530 { "quiet-list", no_argument, NULL, 1 }, 937 { "quiet-list", no_argument, NULL, 1 },
531 { "no-colors", no_argument, NULL, 2 }, 938 { "no-colors", no_argument, NULL, 2 },
532 { "colors", no_argument, NULL, 3 }, 939 { "colors", no_argument, NULL, 3 },
940 { "syslog_relay", no_argument, NULL, 4 },
941 { "syslog-relay", no_argument, NULL, 4 },
942 { "legacy", no_argument, NULL, 4 },
943 { "start-time", required_argument, NULL, 5 },
944 { "size-limit", required_argument, NULL, 6 },
945 { "age-limit", required_argument, NULL, 7 },
533 { "output", required_argument, NULL, 'o' }, 946 { "output", required_argument, NULL, 'o' },
534 { "version", no_argument, NULL, 'v' }, 947 { "version", no_argument, NULL, 'v' },
535 { NULL, 0, NULL, 0} 948 { NULL, 0, NULL, 0}
@@ -537,12 +950,12 @@ int main(int argc, char *argv[])
537 950
538 signal(SIGINT, clean_exit); 951 signal(SIGINT, clean_exit);
539 signal(SIGTERM, clean_exit); 952 signal(SIGTERM, clean_exit);
540#ifndef WIN32 953#ifndef _WIN32
541 signal(SIGQUIT, clean_exit); 954 signal(SIGQUIT, clean_exit);
542 signal(SIGPIPE, SIG_IGN); 955 signal(SIGPIPE, SIG_IGN);
543#endif 956#endif
544 957
545 while ((c = getopt_long(argc, argv, "dhu:nxt:T:m:e:p:qkKo:v", longopts, NULL)) != -1) { 958 while ((c = getopt_long(argc, argv, "dhu:nxt:T:m:M:e:p:qkKo:v", longopts, NULL)) != -1) {
546 switch (c) { 959 switch (c) {
547 case 'd': 960 case 'd':
548 idevice_set_debug_level(1); 961 idevice_set_debug_level(1);
@@ -593,6 +1006,22 @@ int main(int argc, char *argv[])
593 num_msg_filters++; 1006 num_msg_filters++;
594 } 1007 }
595 break; 1008 break;
1009 case 'M':
1010 if (!*optarg) {
1011 fprintf(stderr, "ERROR: reverse message filter string must not be empty!\n");
1012 print_usage(argc, argv, 1);
1013 return 2;
1014 } else {
1015 char **new_msg_filters = realloc(msg_reverse_filters, sizeof(char*) * (num_msg_reverse_filters+1));
1016 if (!new_msg_filters) {
1017 fprintf(stderr, "ERROR: realloc() failed\n");
1018 exit(EXIT_FAILURE);
1019 }
1020 msg_reverse_filters = new_msg_filters;
1021 msg_reverse_filters[num_msg_reverse_filters] = strdup(optarg);
1022 num_msg_reverse_filters++;
1023 }
1024 break;
596 case 't': 1025 case 't':
597 if (!*optarg) { 1026 if (!*optarg) {
598 fprintf(stderr, "ERROR: trigger filter string must not be empty!\n"); 1027 fprintf(stderr, "ERROR: trigger filter string must not be empty!\n");
@@ -647,6 +1076,18 @@ int main(int argc, char *argv[])
647 case 3: 1076 case 3:
648 force_colors = 1; 1077 force_colors = 1;
649 break; 1078 break;
1079 case 4:
1080 force_syslog_relay = 1;
1081 break;
1082 case 5:
1083 start_time = strtoll(optarg, NULL, 10);
1084 break;
1085 case 6:
1086 size_limit = strtoll(optarg, NULL, 10);
1087 break;
1088 case 7:
1089 age_limit = strtoll(optarg, NULL, 10);
1090 break;
650 case 'o': 1091 case 'o':
651 if (!*optarg) { 1092 if (!*optarg) {
652 fprintf(stderr, "ERROR: --output option requires an argument!\n"); 1093 fprintf(stderr, "ERROR: --output option requires an argument!\n");
@@ -719,14 +1160,92 @@ int main(int argc, char *argv[])
719 argc -= optind; 1160 argc -= optind;
720 argv += optind; 1161 argv += optind;
721 1162
1163 if (argc > 0) {
1164 if (!strcmp(argv[0], "pidlist")) {
1165 if (connect_service(1) < 0) {
1166 return 1;
1167 }
1168 plist_t list = NULL;
1169 ostrace_get_pid_list(ostrace, &list);
1170 ostrace_client_free(ostrace);
1171 ostrace = NULL;
1172 idevice_free(device);
1173 device = NULL;
1174 if (!list) {
1175 return 1;
1176 }
1177 print_sorted_pidlist(list);
1178 plist_free(list);
1179 return 0;
1180 } else if (!strcmp(argv[0], "archive")) {
1181 if (force_syslog_relay) {
1182 force_syslog_relay = 0;
1183 }
1184 if (argc < 2) {
1185 fprintf(stderr, "Please specify an output filename.\n");
1186 return 1;
1187 }
1188 FILE* outf = NULL;
1189 if (!strcmp(argv[1], "-")) {
1190 if (isatty(1)) {
1191 fprintf(stderr, "Refusing to directly write to stdout. Pipe the output to another process.\n");
1192 return 1;
1193 }
1194 outf = stdout;
1195 } else {
1196 outf = fopen(argv[1], "w");
1197 }
1198 if (!outf) {
1199 fprintf(stderr, "Failed to open %s: %s\n", argv[1], strerror(errno));
1200 return 1;
1201 }
1202 if (connect_service(1) < 0) {
1203 if (outf != stdout) {
1204 fclose(outf);
1205 }
1206 return 1;
1207 }
1208 plist_t options = plist_new_dict();
1209 if (start_time > 0) {
1210 plist_dict_set_item(options, "StartTime", plist_new_int(start_time));
1211 }
1212 if (size_limit > 0) {
1213 plist_dict_set_item(options, "SizeLimit", plist_new_int(size_limit));
1214 }
1215 if (age_limit > 0) {
1216 plist_dict_set_item(options, "AgeLimit", plist_new_int(age_limit));
1217 }
1218 ostrace_create_archive(ostrace, options, write_callback, outf);
1219 ostrace_client_free(ostrace);
1220 ostrace = NULL;
1221 idevice_free(device);
1222 device = NULL;
1223 if (outf != stdout) {
1224 fclose(outf);
1225 }
1226 return 0;
1227 } else {
1228 fprintf(stderr, "Unknown command '%s'. See --help for valid commands.\n", argv[0]);
1229 return 1;
1230 }
1231 }
1232
722 int num = 0; 1233 int num = 0;
723 idevice_info_t *devices = NULL; 1234 idevice_info_t *devices = NULL;
724 idevice_get_device_list_extended(&devices, &num); 1235 idevice_get_device_list_extended(&devices, &num);
1236 int count = 0;
1237 for (int i = 0; i < num; i++) {
1238 if (devices[i]->conn_type == CONNECTION_NETWORK && use_network) {
1239 count++;
1240 } else if (devices[i]->conn_type == CONNECTION_USBMUXD) {
1241 count++;
1242 }
1243 }
725 idevice_device_list_extended_free(devices); 1244 idevice_device_list_extended_free(devices);
726 if (num == 0) { 1245 if (count == 0) {
727 if (!udid) { 1246 if (!udid) {
728 fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to be available.\n"); 1247 fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to become available.\n");
729 return -1; 1248 return 1;
730 } 1249 }
731 1250
732 fprintf(stderr, "Waiting for device with UDID %s to become available...\n", udid); 1251 fprintf(stderr, "Waiting for device with UDID %s to become available...\n", udid);
@@ -761,6 +1280,13 @@ int main(int argc, char *argv[])
761 } 1280 }
762 free(msg_filters); 1281 free(msg_filters);
763 } 1282 }
1283 if (num_msg_reverse_filters > 0) {
1284 int i;
1285 for (i = 0; i < num_msg_reverse_filters; i++) {
1286 free(msg_reverse_filters[i]);
1287 }
1288 free(msg_reverse_filters);
1289 }
764 if (num_trigger_filters > 0) { 1290 if (num_trigger_filters > 0) {
765 int i; 1291 int i;
766 for (i = 0; i < num_trigger_filters; i++) { 1292 for (i = 0; i < num_trigger_filters; i++) {