summaryrefslogtreecommitdiffstats
path: root/tools/idevicesyslog.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/idevicesyslog.c')
-rw-r--r--tools/idevicesyslog.c812
1 files changed, 713 insertions, 99 deletions
diff --git a/tools/idevicesyslog.c b/tools/idevicesyslog.c
index f2b3a2f..a0e641d 100644
--- a/tools/idevicesyslog.c
+++ b/tools/idevicesyslog.c
@@ -2,169 +2,783 @@
2 * idevicesyslog.c 2 * idevicesyslog.c
3 * Relay the syslog of a device to stdout 3 * Relay the syslog of a device to stdout
4 * 4 *
5 * Copyright (c) 2010-2020 Nikias Bassen, All Rights Reserved.
5 * Copyright (c) 2009 Martin Szulecki All Rights Reserved. 6 * Copyright (c) 2009 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
9 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version. 11 * version 2.1 of the License, or (at your option) any later version.
11 * 12 *
12 * This library is distributed in the hope that it will be useful, 13 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details. 16 * Lesser General Public License for more details.
16 * 17 *
17 * You should have received a copy of the GNU Lesser General Public 18 * 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 * 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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 21 */
21 22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#define TOOL_NAME "idevicesyslog"
28
22#include <stdio.h> 29#include <stdio.h>
23#include <string.h> 30#include <string.h>
24#include <errno.h> 31#include <errno.h>
25#include <signal.h> 32#include <signal.h>
26#include <stdlib.h> 33#include <stdlib.h>
27#include <glib.h> 34#include <unistd.h>
35#include <getopt.h>
36
37#ifdef WIN32
38#include <windows.h>
39#define sleep(x) Sleep(x*1000)
40#endif
28 41
29#include <libimobiledevice/libimobiledevice.h> 42#include <libimobiledevice/libimobiledevice.h>
30#include <libimobiledevice/lockdown.h> 43#include <libimobiledevice/syslog_relay.h>
44#include <libimobiledevice-glue/termcolors.h>
31 45
32static int quit_flag = 0; 46static int quit_flag = 0;
47static int exit_on_disconnect = 0;
48static int show_device_name = 0;
49
50static char* udid = NULL;
51static char** proc_filters = NULL;
52static int num_proc_filters = 0;
53static int proc_filter_excluding = 0;
54
55static int* pid_filters = NULL;
56static int num_pid_filters = 0;
57
58static char** msg_filters = NULL;
59static int num_msg_filters = 0;
60
61static char** trigger_filters = NULL;
62static int num_trigger_filters = 0;
63static char** untrigger_filters = NULL;
64static int num_untrigger_filters = 0;
65static int triggered = 0;
66
67static idevice_t device = NULL;
68static syslog_relay_client_t syslog = NULL;
69
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";
71
72static int use_network = 0;
73
74static char *line = NULL;
75static int line_buffer_size = 0;
76static int lp = 0;
77
78static void add_filter(const char* filterstr)
79{
80 int filter_len = strlen(filterstr);
81 const char* start = filterstr;
82 const char* end = filterstr + filter_len;
83 const char* p = start;
84 while (p <= end) {
85 if ((*p == '|') || (*p == '\0')) {
86 if (p-start > 0) {
87 char* procn = malloc(p-start+1);
88 if (!procn) {
89 fprintf(stderr, "ERROR: malloc() failed\n");
90 exit(EXIT_FAILURE);
91 }
92 memcpy(procn, start, p-start);
93 procn[p-start] = '\0';
94 char* endp = NULL;
95 int pid_value = (int)strtol(procn, &endp, 10);
96 if (!endp || *endp == 0) {
97 int *new_pid_filters = realloc(pid_filters, sizeof(int) * (num_pid_filters+1));
98 if (!new_pid_filters) {
99 fprintf(stderr, "ERROR: realloc() failed\n");
100 exit(EXIT_FAILURE);
101 }
102 pid_filters = new_pid_filters;
103 pid_filters[num_pid_filters] = pid_value;
104 num_pid_filters++;
105 } else {
106 char **new_proc_filters = realloc(proc_filters, sizeof(char*) * (num_proc_filters+1));
107 if (!new_proc_filters) {
108 fprintf(stderr, "ERROR: realloc() failed\n");
109 exit(EXIT_FAILURE);
110 }
111 proc_filters = new_proc_filters;
112 proc_filters[num_proc_filters] = procn;
113 num_proc_filters++;
114 }
115 }
116 start = p+1;
117 }
118 p++;
119 }
120}
121
122static int find_char(char c, char** p, const char* end)
123{
124 while ((**p != c) && (*p < end)) {
125 (*p)++;
126 }
127 return (**p == c);
128}
129
130static void stop_logging(void);
131
132static void syslog_callback(char c, void *user_data)
133{
134 if (lp >= line_buffer_size-1) {
135 line_buffer_size+=1024;
136 char* _line = realloc(line, line_buffer_size);
137 if (!_line) {
138 fprintf(stderr, "ERROR: realloc failed\n");
139 exit(EXIT_FAILURE);
140 }
141 line = _line;
142 }
143 line[lp++] = c;
144 if (c == '\0') {
145 int shall_print = 0;
146 int trigger_off = 0;
147 lp--;
148 char* linep = &line[0];
149 do {
150 if (lp < 16) {
151 shall_print = 1;
152 cprintf(FG_WHITE);
153 break;
154 }
155
156 if (line[3] == ' ' && line[6] == ' ' && line[15] == ' ') {
157 char* end = &line[lp];
158 char* p = &line[16];
159
160 /* device name */
161 char* device_name_start = p;
162 char* device_name_end = p;
163 if (!find_char(' ', &p, end)) break;
164 device_name_end = p;
165 p++;
166
167 /* check if we have any triggers/untriggers */
168 if (num_untrigger_filters > 0 && triggered) {
169 int found = 0;
170 int i;
171 for (i = 0; i < num_untrigger_filters; i++) {
172 if (strstr(device_name_end+1, untrigger_filters[i])) {
173 found = 1;
174 break;
175 }
176 }
177 if (!found) {
178 shall_print = 1;
179 } else {
180 shall_print = 1;
181 trigger_off = 1;
182 }
183 } else if (num_trigger_filters > 0 && !triggered) {
184 int found = 0;
185 int i;
186 for (i = 0; i < num_trigger_filters; i++) {
187 if (strstr(device_name_end+1, trigger_filters[i])) {
188 found = 1;
189 break;
190 }
191 }
192 if (!found) {
193 shall_print = 0;
194 break;
195 }
196 triggered = 1;
197 shall_print = 1;
198 } else if (num_trigger_filters == 0 && num_untrigger_filters > 0 && !triggered) {
199 shall_print = 0;
200 quit_flag++;
201 break;
202 }
203
204 /* check message filters */
205 if (num_msg_filters > 0) {
206 int found = 0;
207 int i;
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 }
220
221 /* process name */
222 char* proc_name_start = p;
223 char* proc_name_end = p;
224 if (!find_char('[', &p, end)) break;
225 char* process_name_start = proc_name_start;
226 char* process_name_end = p;
227 char* pid_start = p+1;
228 char* pp = process_name_start;
229 if (find_char('(', &pp, p)) {
230 process_name_end = pp;
231 }
232 if (!find_char(']', &p, end)) break;
233 p++;
234 if (*p != ' ') break;
235 proc_name_end = p;
236 p++;
237
238 int proc_matched = 0;
239 if (num_pid_filters > 0) {
240 char* endp = NULL;
241 int pid_value = (int)strtol(pid_start, &endp, 10);
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;
272 } else {
273 if (num_pid_filters > 0 || num_proc_filters > 0) {
274 shall_print = 0;
275 break;
276 }
277 }
278
279 /* log level */
280 char* level_start = p;
281 char* level_end = p;
282 const char* level_color = NULL;
283 if (!strncmp(p, "<Notice>:", 9)) {
284 level_end += 9;
285 level_color = FG_GREEN;
286 } else if (!strncmp(p, "<Error>:", 8)) {
287 level_end += 8;
288 level_color = FG_RED;
289 } else if (!strncmp(p, "<Warning>:", 10)) {
290 level_end += 10;
291 level_color = FG_YELLOW;
292 } else if (!strncmp(p, "<Debug>:", 8)) {
293 level_end += 8;
294 level_color = FG_MAGENTA;
295 } else {
296 level_color = FG_WHITE;
297 }
298
299 /* write date and time */
300 cprintf(FG_LIGHT_GRAY);
301 fwrite(line, 1, 16, stdout);
302
303 if (show_device_name) {
304 /* write device name */
305 cprintf(FG_DARK_YELLOW);
306 fwrite(device_name_start, 1, device_name_end-device_name_start+1, stdout);
307 cprintf(COLOR_RESET);
308 }
309
310 /* write process name */
311 cprintf(FG_BRIGHT_CYAN);
312 fwrite(process_name_start, 1, process_name_end-process_name_start, stdout);
313 cprintf(FG_CYAN);
314 fwrite(process_name_end, 1, proc_name_end-process_name_end+1, stdout);
315
316 /* write log level */
317 cprintf(level_color);
318 if (level_end > level_start) {
319 fwrite(level_start, 1, level_end-level_start, stdout);
320 p = level_end;
321 }
322
323 lp -= p - linep;
324 linep = p;
325
326 cprintf(FG_WHITE);
327
328 } else {
329 shall_print = 1;
330 cprintf(FG_WHITE);
331 }
332 } while (0);
333
334 if ((num_msg_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);
336 cprintf(COLOR_RESET);
337 fflush(stdout);
338 if (trigger_off) {
339 triggered = 0;
340 }
341 }
342 line[0] = '\0';
343 lp = 0;
344 return;
345 }
346}
347
348static int start_logging(void)
349{
350 idevice_error_t ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
351 if (ret != IDEVICE_E_SUCCESS) {
352 fprintf(stderr, "Device with udid %s not found!?\n", udid);
353 return -1;
354 }
355
356 lockdownd_client_t lockdown = NULL;
357 lockdownd_error_t lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME);
358 if (lerr != LOCKDOWN_E_SUCCESS) {
359 fprintf(stderr, "ERROR: Could not connect to lockdownd: %d\n", lerr);
360 idevice_free(device);
361 device = NULL;
362 return -1;
363 }
364
365 /* start syslog_relay service */
366 lockdownd_service_descriptor_t svc = NULL;
367 lerr = lockdownd_start_service(lockdown, SYSLOG_RELAY_SERVICE_NAME, &svc);
368 if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) {
369 fprintf(stderr, "*** Device is passcode protected, enter passcode on the device to continue ***\n");
370 while (!quit_flag) {
371 lerr = lockdownd_start_service(lockdown, SYSLOG_RELAY_SERVICE_NAME, &svc);
372 if (lerr != LOCKDOWN_E_PASSWORD_PROTECTED) {
373 break;
374 }
375 sleep(1);
376 }
377 }
378 if (lerr != LOCKDOWN_E_SUCCESS) {
379 fprintf(stderr, "ERROR: Could not connect to lockdownd: %d\n", lerr);
380 idevice_free(device);
381 device = NULL;
382 return -1;
383 }
384 lockdownd_client_free(lockdown);
385
386 /* connect to syslog_relay service */
387 syslog_relay_error_t serr = SYSLOG_RELAY_E_UNKNOWN_ERROR;
388 serr = syslog_relay_client_new(device, svc, &syslog);
389 lockdownd_service_descriptor_free(svc);
390 if (serr != SYSLOG_RELAY_E_SUCCESS) {
391 fprintf(stderr, "ERROR: Could not start service com.apple.syslog_relay.\n");
392 idevice_free(device);
393 device = NULL;
394 return -1;
395 }
396
397 /* start capturing syslog */
398 serr = syslog_relay_start_capture_raw(syslog, syslog_callback, NULL);
399 if (serr != SYSLOG_RELAY_E_SUCCESS) {
400 fprintf(stderr, "ERROR: Unable tot start capturing syslog.\n");
401 syslog_relay_client_free(syslog);
402 syslog = NULL;
403 idevice_free(device);
404 device = NULL;
405 return -1;
406 }
407
408 fprintf(stdout, "[connected:%s]\n", udid);
409 fflush(stdout);
410
411 return 0;
412}
413
414static void stop_logging(void)
415{
416 fflush(stdout);
33 417
34void print_usage(int argc, char **argv); 418 if (syslog) {
419 syslog_relay_client_free(syslog);
420 syslog = NULL;
421 }
422
423 if (device) {
424 idevice_free(device);
425 device = NULL;
426 }
427}
428
429static void device_event_cb(const idevice_event_t* event, void* userdata)
430{
431 if (use_network && event->conn_type != CONNECTION_NETWORK) {
432 return;
433 }
434 if (!use_network && event->conn_type != CONNECTION_USBMUXD) {
435 return;
436 }
437 if (event->event == IDEVICE_DEVICE_ADD) {
438 if (!syslog) {
439 if (!udid) {
440 udid = strdup(event->udid);
441 }
442 if (strcmp(udid, event->udid) == 0) {
443 if (start_logging() != 0) {
444 fprintf(stderr, "Could not start logger for udid %s\n", udid);
445 }
446 }
447 }
448 } else if (event->event == IDEVICE_DEVICE_REMOVE) {
449 if (syslog && (strcmp(udid, event->udid) == 0)) {
450 stop_logging();
451 fprintf(stdout, "[disconnected:%s]\n", udid);
452 if (exit_on_disconnect) {
453 quit_flag++;
454 }
455 }
456 }
457}
35 458
36/** 459/**
37 * signal handler function for cleaning up properly 460 * signal handler function for cleaning up properly
38 */ 461 */
39static void clean_exit(int sig) 462static void clean_exit(int sig)
40{ 463{
41 fprintf(stderr, "Exiting...\n"); 464 fprintf(stderr, "\nExiting...\n");
42 quit_flag++; 465 quit_flag++;
43} 466}
44 467
468static void print_usage(int argc, char **argv, int is_error)
469{
470 char *name = strrchr(argv[0], '/');
471 fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0]));
472 fprintf(is_error ? stderr : stdout,
473 "\n"
474 "Relay syslog of a connected device.\n"
475 "\n"
476 "OPTIONS:\n"
477 " -u, --udid UDID target specific device by UDID\n"
478 " -n, --network connect to network device\n"
479 " -x, --exit exit when device disconnects\n"
480 " -h, --help prints usage information\n"
481 " -d, --debug enable communication debugging\n"
482 " -v, --version prints version information\n"
483 " --no-colors disable colored output\n"
484 " -o, --output FILE write to FILE instead of stdout\n"
485 " (existing FILE will be overwritten)\n"
486 " --colors force writing colored output, e.g. for --output\n"
487 "\n"
488 "FILTER OPTIONS:\n"
489 " -m, --match STRING only print messages that contain STRING\n"
490 " -t, --trigger STRING start logging when matching STRING\n"
491 " -T, --untrigger STRING stop logging when matching STRING\n"
492 " -p, --process PROCESS only print messages from matching process(es)\n"
493 " -e, --exclude PROCESS print all messages except matching process(es)\n"
494 " PROCESS is a process name or multiple process names\n"
495 " separated by \"|\".\n"
496 " -q, --quiet set a filter to exclude common noisy processes\n"
497 " --quiet-list prints the list of processes for --quiet and exits\n"
498 " -k, --kernel only print kernel messages\n"
499 " -K, --no-kernel suppress kernel messages\n"
500 "\n"
501 "For filter examples consult idevicesyslog(1) man page.\n"
502 "\n"
503 "Homepage: <" PACKAGE_URL ">\n"
504 "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
505 );
506}
507
45int main(int argc, char *argv[]) 508int main(int argc, char *argv[])
46{ 509{
47 lockdownd_client_t client = NULL; 510 int include_filter = 0;
48 idevice_t phone = NULL; 511 int exclude_filter = 0;
49 idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; 512 int include_kernel = 0;
50 int i; 513 int exclude_kernel = 0;
51 char uuid[41]; 514 int force_colors = 0;
52 uint16_t port = 0; 515 int c = 0;
53 uuid[0] = 0; 516 const struct option longopts[] = {
517 { "debug", no_argument, NULL, 'd' },
518 { "help", no_argument, NULL, 'h' },
519 { "udid", required_argument, NULL, 'u' },
520 { "network", no_argument, NULL, 'n' },
521 { "exit", no_argument, NULL, 'x' },
522 { "trigger", required_argument, NULL, 't' },
523 { "untrigger", required_argument, NULL, 'T' },
524 { "match", required_argument, NULL, 'm' },
525 { "process", required_argument, NULL, 'p' },
526 { "exclude", required_argument, NULL, 'e' },
527 { "quiet", no_argument, NULL, 'q' },
528 { "kernel", no_argument, NULL, 'k' },
529 { "no-kernel", no_argument, NULL, 'K' },
530 { "quiet-list", no_argument, NULL, 1 },
531 { "no-colors", no_argument, NULL, 2 },
532 { "colors", no_argument, NULL, 3 },
533 { "output", required_argument, NULL, 'o' },
534 { "version", no_argument, NULL, 'v' },
535 { NULL, 0, NULL, 0}
536 };
54 537
55 signal(SIGINT, clean_exit); 538 signal(SIGINT, clean_exit);
56 signal(SIGQUIT, clean_exit);
57 signal(SIGTERM, clean_exit); 539 signal(SIGTERM, clean_exit);
540#ifndef WIN32
541 signal(SIGQUIT, clean_exit);
58 signal(SIGPIPE, SIG_IGN); 542 signal(SIGPIPE, SIG_IGN);
543#endif
59 544
60 /* parse cmdline args */ 545 while ((c = getopt_long(argc, argv, "dhu:nxt:T:m:e:p:qkKo:v", longopts, NULL)) != -1) {
61 for (i = 1; i < argc; i++) { 546 switch (c) {
62 if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { 547 case 'd':
63 idevice_set_debug_level(1); 548 idevice_set_debug_level(1);
64 continue; 549 break;
65 } 550 case 'u':
66 else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--uuid")) { 551 if (!*optarg) {
67 i++; 552 fprintf(stderr, "ERROR: UDID must not be empty!\n");
68 if (!argv[i] || (strlen(argv[i]) != 40)) { 553 print_usage(argc, argv, 1);
69 print_usage(argc, argv); 554 return 2;
70 return 0; 555 }
71 } 556 free(udid);
72 strcpy(uuid, argv[i]); 557 udid = strdup(optarg);
73 continue; 558 break;
74 } 559 case 'n':
75 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { 560 use_network = 1;
76 print_usage(argc, argv); 561 break;
562 case 'q':
563 exclude_filter++;
564 add_filter(QUIET_FILTER);
565 break;
566 case 'p':
567 case 'e':
568 if (c == 'p') {
569 include_filter++;
570 } else if (c == 'e') {
571 exclude_filter++;
572 }
573 if (!*optarg) {
574 fprintf(stderr, "ERROR: filter string must not be empty!\n");
575 print_usage(argc, argv, 1);
576 return 2;
577 }
578 add_filter(optarg);
579 break;
580 case 'm':
581 if (!*optarg) {
582 fprintf(stderr, "ERROR: message filter string must not be empty!\n");
583 print_usage(argc, argv, 1);
584 return 2;
585 } else {
586 char **new_msg_filters = realloc(msg_filters, sizeof(char*) * (num_msg_filters+1));
587 if (!new_msg_filters) {
588 fprintf(stderr, "ERROR: realloc() failed\n");
589 exit(EXIT_FAILURE);
590 }
591 msg_filters = new_msg_filters;
592 msg_filters[num_msg_filters] = strdup(optarg);
593 num_msg_filters++;
594 }
595 break;
596 case 't':
597 if (!*optarg) {
598 fprintf(stderr, "ERROR: trigger filter string must not be empty!\n");
599 print_usage(argc, argv, 1);
600 return 2;
601 } else {
602 char **new_trigger_filters = realloc(trigger_filters, sizeof(char*) * (num_trigger_filters+1));
603 if (!new_trigger_filters) {
604 fprintf(stderr, "ERROR: realloc() failed\n");
605 exit(EXIT_FAILURE);
606 }
607 trigger_filters = new_trigger_filters;
608 trigger_filters[num_trigger_filters] = strdup(optarg);
609 num_trigger_filters++;
610 }
611 break;
612 case 'T':
613 if (!*optarg) {
614 fprintf(stderr, "ERROR: untrigger filter string must not be empty!\n");
615 print_usage(argc, argv, 1);
616 return 2;
617 } else {
618 char **new_untrigger_filters = realloc(untrigger_filters, sizeof(char*) * (num_untrigger_filters+1));
619 if (!new_untrigger_filters) {
620 fprintf(stderr, "ERROR: realloc() failed\n");
621 exit(EXIT_FAILURE);
622 }
623 untrigger_filters = new_untrigger_filters;
624 untrigger_filters[num_untrigger_filters] = strdup(optarg);
625 num_untrigger_filters++;
626 }
627 break;
628 case 'k':
629 include_kernel++;
630 break;
631 case 'K':
632 exclude_kernel++;
633 break;
634 case 'x':
635 exit_on_disconnect = 1;
636 break;
637 case 'h':
638 print_usage(argc, argv, 0);
639 return 0;
640 case 1: {
641 printf("%s\n", QUIET_FILTER);
77 return 0; 642 return 0;
78 } 643 }
79 else { 644 case 2:
80 print_usage(argc, argv); 645 term_colors_set_enabled(0);
646 break;
647 case 3:
648 force_colors = 1;
649 break;
650 case 'o':
651 if (!*optarg) {
652 fprintf(stderr, "ERROR: --output option requires an argument!\n");
653 print_usage(argc, argv, 1);
654 return 2;
655 } else {
656 if (freopen(optarg, "w", stdout) == NULL) {
657 fprintf(stderr, "ERROR: Failed to open output file '%s' for writing: %s\n", optarg, strerror(errno));
658 return 1;
659 }
660 term_colors_set_enabled(0);
661 }
662 break;
663 case 'v':
664 printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
81 return 0; 665 return 0;
666 default:
667 print_usage(argc, argv, 1);
668 return 2;
82 } 669 }
83 } 670 }
84 671
85 if (uuid[0] != 0) { 672 if (force_colors) {
86 ret = idevice_new(&phone, uuid); 673 term_colors_set_enabled(1);
87 if (ret != IDEVICE_E_SUCCESS) {
88 printf("No device found with uuid %s, is it plugged in?\n", uuid);
89 return -1;
90 }
91 } 674 }
92 else 675
93 { 676 if (include_kernel > 0 && exclude_kernel > 0) {
94 ret = idevice_new(&phone, NULL); 677 fprintf(stderr, "ERROR: -k and -K cannot be used together.\n");
95 if (ret != IDEVICE_E_SUCCESS) { 678 print_usage(argc, argv, 1);
96 printf("No device found, is it plugged in?\n"); 679 return 2;
97 return -1;
98 }
99 } 680 }
100 681
101 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "idevicesyslog")) { 682 if (include_filter > 0 && exclude_filter > 0) {
102 idevice_free(phone); 683 fprintf(stderr, "ERROR: -p and -e/-q cannot be used together.\n");
103 return -1; 684 print_usage(argc, argv, 1);
685 return 2;
686 }
687 if (include_filter > 0 && exclude_kernel > 0) {
688 fprintf(stderr, "ERROR: -p and -K cannot be used together.\n");
689 print_usage(argc, argv, 1);
690 return 2;
104 } 691 }
105 692
106 /* start syslog_relay service and retrieve port */ 693 if (exclude_filter > 0) {
107 ret = lockdownd_start_service(client, "com.apple.syslog_relay", &port); 694 proc_filter_excluding = 1;
108 if ((ret == LOCKDOWN_E_SUCCESS) && port) { 695 if (include_kernel) {
109 lockdownd_client_free(client); 696 int i = 0;
110 697 for (i = 0; i < num_proc_filters; i++) {
111 /* connect to socket relay messages */ 698 if (!strcmp(proc_filters[i], "kernel")) {
112 idevice_connection_t conn = NULL; 699 free(proc_filters[i]);
113 if ((idevice_connect(phone, port, &conn) != IDEVICE_E_SUCCESS) || !conn) { 700 proc_filters[i] = NULL;
114 printf("ERROR: Could not open usbmux connection.\n");
115 } else {
116 while (!quit_flag) {
117 char *receive = NULL;
118 uint32_t datalen = 0, bytes = 0, recv_bytes = 0;
119
120 ret = idevice_connection_receive(conn, (char *) &datalen, sizeof(datalen), &bytes);
121 if (ret < 0) {
122 fprintf(stderr, "Error receiving data. Exiting...\n");
123 break;
124 } 701 }
702 }
703 } else if (exclude_kernel) {
704 add_filter("kernel");
705 }
706 } else {
707 if (include_kernel) {
708 add_filter("kernel");
709 } else if (exclude_kernel) {
710 proc_filter_excluding = 1;
711 add_filter("kernel");
712 }
713 }
125 714
126 datalen = GUINT32_FROM_BE(datalen); 715 if (num_untrigger_filters > 0 && num_trigger_filters == 0) {
716 triggered = 1;
717 }
127 718
128 if (datalen == 0) 719 argc -= optind;
129 continue; 720 argv += optind;
130 721
131 recv_bytes += bytes; 722 int num = 0;
132 receive = (char *) malloc(sizeof(char) * datalen); 723 idevice_info_t *devices = NULL;
724 idevice_get_device_list_extended(&devices, &num);
725 idevice_device_list_extended_free(devices);
726 if (num == 0) {
727 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");
729 return -1;
730 }
133 731
134 while (!quit_flag && (recv_bytes <= datalen)) { 732 fprintf(stderr, "Waiting for device with UDID %s to become available...\n", udid);
135 ret = idevice_connection_receive(conn, receive, datalen, &bytes); 733 }
136 734
137 if (bytes == 0) 735 line_buffer_size = 1024;
138 break; 736 line = malloc(line_buffer_size);
139 737
140 recv_bytes += bytes; 738 idevice_subscription_context_t context = NULL;
739 idevice_events_subscribe(&context, device_event_cb, NULL);
141 740
142 fwrite(receive, sizeof(char), bytes, stdout); 741 while (!quit_flag) {
143 } 742 sleep(1);
743 }
744 idevice_events_unsubscribe(context);
745 stop_logging();
144 746
145 free(receive); 747 if (num_proc_filters > 0) {
146 } 748 int i;
749 for (i = 0; i < num_proc_filters; i++) {
750 free(proc_filters[i]);
147 } 751 }
148 idevice_disconnect(conn); 752 free(proc_filters);
149 } else { 753 }
150 printf("ERROR: Could not start service com.apple.syslog_relay.\n"); 754 if (num_pid_filters > 0) {
755 free(pid_filters);
756 }
757 if (num_msg_filters > 0) {
758 int i;
759 for (i = 0; i < num_msg_filters; i++) {
760 free(msg_filters[i]);
761 }
762 free(msg_filters);
763 }
764 if (num_trigger_filters > 0) {
765 int i;
766 for (i = 0; i < num_trigger_filters; i++) {
767 free(trigger_filters[i]);
768 }
769 free(trigger_filters);
770 }
771 if (num_untrigger_filters > 0) {
772 int i;
773 for (i = 0; i < num_untrigger_filters; i++) {
774 free(untrigger_filters[i]);
775 }
776 free(untrigger_filters);
151 } 777 }
152 778
153 idevice_free(phone); 779 free(line);
154 780
155 return 0; 781 free(udid);
156}
157 782
158void print_usage(int argc, char **argv) 783 return 0;
159{
160 char *name = NULL;
161
162 name = strrchr(argv[0], '/');
163 printf("Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0]));
164 printf("Relay syslog of a connected iPhone/iPod Touch.\n\n");
165 printf(" -d, --debug\t\tenable communication debugging\n");
166 printf(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n");
167 printf(" -h, --help\t\tprints usage information\n");
168 printf("\n");
169} 784}
170