summaryrefslogtreecommitdiffstats
path: root/tools/idevicesyslog.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/idevicesyslog.c')
-rw-r--r--tools/idevicesyslog.c506
1 files changed, 499 insertions, 7 deletions
diff --git a/tools/idevicesyslog.c b/tools/idevicesyslog.c
index 619b51b..b3a754f 100644
--- a/tools/idevicesyslog.c
+++ b/tools/idevicesyslog.c
@@ -2,7 +2,7 @@
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-2019 Nikias Bassen, All Rights Reserved. 5 * Copyright (c) 2010-2020 Nikias Bassen, All Rights Reserved.
6 * Copyright (c) 2009 Martin Szulecki All Rights Reserved. 6 * Copyright (c) 2009 Martin Szulecki All Rights Reserved.
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
@@ -42,19 +42,325 @@
42 42
43static int quit_flag = 0; 43static int quit_flag = 0;
44static int exit_on_disconnect = 0; 44static int exit_on_disconnect = 0;
45static int use_colors = 0;
46static int show_device_name = 0;
45 47
46static char* udid = NULL; 48static char* udid = NULL;
49static char** proc_filters = NULL;
50static int num_proc_filters = 0;
51static int proc_filter_excluding = 0;
52
53static int* pid_filters = NULL;
54static int num_pid_filters = 0;
55
56static char** msg_filters = NULL;
57static int num_msg_filters = 0;
58
59static char** trigger_filters = NULL;
60static int num_trigger_filters = 0;
61static char** untrigger_filters = NULL;
62static int num_untrigger_filters = 0;
63static int triggered = 0;
47 64
48static idevice_t device = NULL; 65static idevice_t device = NULL;
49static syslog_relay_client_t syslog = NULL; 66static syslog_relay_client_t syslog = NULL;
50 67
68static const char QUIET_FILTER[] = "CommCenter|SpringBoard|UserEventAgent|WirelessRadioManagerd|aggregated|appstored|backboardd|biometrickitd|bluetoothd|callservicesd|contextstored|corespeechd|dasd|gpsd|homed|identityservicesd|itunesstored|kernel|locationd|mDNSResponder|mediaremoted|mediaserverd|navd|nsurlsessiond|powerd|rapportd|routined|runningboardd|sharingd|symptomsd|thermalmonitord|useractivityd|wifid";
69
51enum idevice_options lookup_opts = IDEVICE_LOOKUP_USBMUX | IDEVICE_LOOKUP_NETWORK; 70enum idevice_options lookup_opts = IDEVICE_LOOKUP_USBMUX | IDEVICE_LOOKUP_NETWORK;
52 71
72static char *line = NULL;
73static int line_buffer_size = 0;
74static int lp = 0;
75
76#define COLOR_RESET "\e[m"
77#define COLOR_NORMAL "\e[0m"
78#define COLOR_DARK "\e[2m"
79#define COLOR_RED "\e[0;31m"
80#define COLOR_DARK_RED "\e[2;31m"
81#define COLOR_GREEN "\e[0;32m"
82#define COLOR_DARK_GREEN "\e[2;32m"
83#define COLOR_YELLOW "\e[0;33m"
84#define COLOR_DARK_YELLOW "\e[2;33m"
85#define COLOR_BLUE "\e[0;34m"
86#define COLOR_DARK_BLUE "\e[2;34m"
87#define COLOR_MAGENTA "\e[0;35m"
88#define COLOR_DARK_MAGENTA "\e[2;35m"
89#define COLOR_CYAN "\e[0;36m"
90#define COLOR_BRIGHT_CYAN "\e[1;36m"
91#define COLOR_DARK_CYAN "\e[2;36m"
92#define COLOR_WHITE "\e[1;37m"
93#define COLOR_DARK_WHITE "\e[0;37m"
94
95#define TEXT_COLOR(x) if (use_colors) { fwrite(x, 1, sizeof(x), stdout); }
96
97static void add_filter(const char* filterstr)
98{
99 int filter_len = strlen(filterstr);
100 const char* start = filterstr;
101 const char* end = filterstr + filter_len;
102 const char* p = start;
103 while (p <= end) {
104 if ((*p == '|') || (*p == '\0')) {
105 if (p-start > 0) {
106 char* procn = malloc(p-start+1);
107 if (!procn) {
108 fprintf(stderr, "ERROR: malloc() failed\n");
109 exit(EXIT_FAILURE);
110 }
111 memcpy(procn, start, p-start);
112 procn[p-start] = '\0';
113 char* endp = NULL;
114 int pid_value = (int)strtol(procn, &endp, 10);
115 if (!endp || *endp == 0) {
116 int *new_pid_filters = realloc(pid_filters, sizeof(int) * (num_pid_filters+1));
117 if (!new_pid_filters) {
118 fprintf(stderr, "ERROR: realloc() failed\n");
119 exit(EXIT_FAILURE);
120 }
121 pid_filters = new_pid_filters;
122 pid_filters[num_pid_filters] = pid_value;
123 num_pid_filters++;
124 } else {
125 char **new_proc_filters = realloc(proc_filters, sizeof(char*) * (num_proc_filters+1));
126 if (!new_proc_filters) {
127 fprintf(stderr, "ERROR: realloc() failed\n");
128 exit(EXIT_FAILURE);
129 }
130 proc_filters = new_proc_filters;
131 proc_filters[num_proc_filters] = procn;
132 num_proc_filters++;
133 }
134 }
135 start = p+1;
136 }
137 p++;
138 }
139}
140
141static int find_char(char c, char** p, char* end)
142{
143 while ((**p != c) && (*p < end)) {
144 (*p)++;
145 }
146 return (**p == c);
147}
148
149static void stop_logging(void);
150
53static void syslog_callback(char c, void *user_data) 151static void syslog_callback(char c, void *user_data)
54{ 152{
55 putchar(c); 153 if (lp >= line_buffer_size-1) {
56 if (c == '\n') { 154 line_buffer_size+=1024;
57 fflush(stdout); 155 char* _line = realloc(line, line_buffer_size);
156 if (!_line) {
157 fprintf(stderr, "ERROR: realloc failed\n");
158 exit(EXIT_FAILURE);
159 }
160 line = _line;
161 }
162 line[lp++] = c;
163 if (c == '\0') {
164 int shall_print = 0;
165 int trigger_off = 0;
166 lp--;
167 char* linep = &line[0];
168 do {
169 if (lp < 16) {
170 shall_print = 1;
171 TEXT_COLOR(COLOR_WHITE);
172 break;
173 } else if (line[3] == ' ' && line[6] == ' ' && line[15] == ' ') {
174 char* end = &line[lp];
175 char* p = &line[16];
176
177 /* device name */
178 char* device_name_start = p;
179 char* device_name_end = p;
180 if (!find_char(' ', &p, end)) break;
181 device_name_end = p;
182 p++;
183
184 /* check if we have any triggers/untriggers */
185 if (num_untrigger_filters > 0 && triggered) {
186 int found = 0;
187 int i;
188 for (i = 0; i < num_untrigger_filters; i++) {
189 if (strstr(device_name_end+1, untrigger_filters[i])) {
190 found = 1;
191 break;
192 }
193 }
194 if (!found) {
195 shall_print = 1;
196 } else {
197 shall_print = 1;
198 trigger_off = 1;
199 }
200 } else if (num_trigger_filters > 0 && !triggered) {
201 int found = 0;
202 int i;
203 for (i = 0; i < num_trigger_filters; i++) {
204 if (strstr(device_name_end+1, trigger_filters[i])) {
205 found = 1;
206 break;
207 }
208 }
209 if (!found) {
210 shall_print = 0;
211 break;
212 } else {
213 triggered = 1;
214 shall_print = 1;
215 }
216 } else if (num_trigger_filters == 0 && num_untrigger_filters > 0 && !triggered) {
217 shall_print = 0;
218 quit_flag++;
219 break;
220 }
221
222 /* check message filters */
223 if (num_msg_filters > 0) {
224 int found = 0;
225 int i;
226 for (i = 0; i < num_msg_filters; i++) {
227 if (strstr(device_name_end+1, msg_filters[i])) {
228 found = 1;
229 break;
230 }
231 }
232 if (!found) {
233 shall_print = 0;
234 break;
235 } else {
236 shall_print = 1;
237 }
238 }
239
240 /* process name */
241 char* proc_name_start = p;
242 char* proc_name_end = p;
243 if (!find_char('[', &p, end)) break;
244 char* process_name_start = proc_name_start;
245 char* process_name_end = p;
246 char* pid_start = p+1;
247 char* pp = process_name_start;
248 if (find_char('(', &pp, p)) {
249 process_name_end = pp;
250 }
251 if (!find_char(']', &p, end)) break;
252 p++;
253 if (*p != ' ') break;
254 proc_name_end = p;
255 p++;
256
257 int proc_matched = 0;
258 if (num_pid_filters > 0) {
259 char* endp = NULL;
260 int pid_value = (int)strtol(pid_start, &endp, 10);
261 if (endp && (*endp == ']')) {
262 int found = proc_filter_excluding;
263 int i = 0;
264 for (i = 0; i < num_pid_filters; i++) {
265 if (pid_value == pid_filters[i]) {
266 found = !proc_filter_excluding;
267 break;
268 }
269 }
270 if (found) {
271 proc_matched = 1;
272 }
273 }
274 }
275 if (num_proc_filters > 0 && !proc_matched) {
276 int found = proc_filter_excluding;
277 int i = 0;
278 for (i = 0; i < num_proc_filters; i++) {
279 if (!proc_filters[i]) continue;
280 if (strncmp(proc_filters[i], process_name_start, process_name_end-process_name_start) == 0) {
281 found = !proc_filter_excluding;
282 break;
283 }
284 }
285 if (found) {
286 proc_matched = 1;
287 }
288 }
289 if (proc_matched) {
290 shall_print = 1;
291 } else {
292 if (num_pid_filters > 0 || num_proc_filters > 0) {
293 shall_print = 0;
294 break;
295 }
296 }
297
298 /* log level */
299 char* level_start = p;
300 char* level_end = p;
301 const char* level_color = NULL;
302 if (!strncmp(p, "<Notice>:", 9)) {
303 level_end += 9;
304 level_color = COLOR_GREEN;
305 } else if (!strncmp(p, "<Error>:", 8)) {
306 level_end += 8;
307 level_color = COLOR_RED;
308 } else if (!strncmp(p, "<Warning>:", 10)) {
309 level_end += 10;
310 level_color = COLOR_YELLOW;
311 } else if (!strncmp(p, "<Debug>:", 8)) {
312 level_end += 8;
313 level_color = COLOR_MAGENTA;
314 } else {
315 level_color = COLOR_WHITE;
316 }
317
318 /* write date and time */
319 TEXT_COLOR(COLOR_DARK_WHITE);
320 fwrite(line, 1, 16, stdout);
321
322 if (show_device_name) {
323 /* write device name */
324 TEXT_COLOR(COLOR_DARK_YELLOW);
325 fwrite(device_name_start, 1, device_name_end-device_name_start+1, stdout);
326 TEXT_COLOR(COLOR_RESET);
327 }
328
329 /* write process name */
330 TEXT_COLOR(COLOR_BRIGHT_CYAN);
331 fwrite(process_name_start, 1, process_name_end-process_name_start, stdout);
332 TEXT_COLOR(COLOR_CYAN);
333 fwrite(process_name_end, 1, proc_name_end-process_name_end+1, stdout);
334
335 /* write log level */
336 TEXT_COLOR(level_color);
337 if (level_end > level_start) {
338 fwrite(level_start, 1, level_end-level_start, stdout);
339 p = level_end;
340 }
341
342 lp -= p - linep;
343 linep = p;
344
345 TEXT_COLOR(COLOR_WHITE);
346
347 } else {
348 shall_print = 1;
349 TEXT_COLOR(COLOR_WHITE);
350 }
351 } while (0);
352
353 if ((num_msg_filters == 0 && num_proc_filters == 0 && num_pid_filters == 0 && num_trigger_filters == 0 && num_untrigger_filters == 0) || shall_print) {
354 fwrite(linep, 1, lp, stdout);
355 TEXT_COLOR(COLOR_RESET);
356 fflush(stdout);
357 if (trigger_off) {
358 triggered = 0;
359 }
360 }
361 line[0] = '\0';
362 lp = 0;
363 return;
58 } 364 }
59} 365}
60 366
@@ -108,7 +414,7 @@ static int start_logging(void)
108 } 414 }
109 415
110 /* start capturing syslog */ 416 /* start capturing syslog */
111 serr = syslog_relay_start_capture(syslog, syslog_callback, NULL); 417 serr = syslog_relay_start_capture_raw(syslog, syslog_callback, NULL);
112 if (serr != SYSLOG_RELAY_E_SUCCESS) { 418 if (serr != SYSLOG_RELAY_E_SUCCESS) {
113 fprintf(stderr, "ERROR: Unable tot start capturing syslog.\n"); 419 fprintf(stderr, "ERROR: Unable tot start capturing syslog.\n");
114 syslog_relay_client_free(syslog); 420 syslog_relay_client_free(syslog);
@@ -179,11 +485,25 @@ static void print_usage(int argc, char **argv, int is_error)
179 fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0])); 485 fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0]));
180 fprintf(is_error ? stderr : stdout, 486 fprintf(is_error ? stderr : stdout,
181 "Relay syslog of a connected device.\n\n" \ 487 "Relay syslog of a connected device.\n\n" \
488 "OPTIONS:\n" \
182 " -u, --udid UDID target specific device by UDID\n" \ 489 " -u, --udid UDID target specific device by UDID\n" \
183 " -n, --network connect to network device even if available via USB\n" \ 490 " -n, --network connect to network device even if available via USB\n" \
491 " -x, --exit exit when device disconnects\n" \
184 " -h, --help prints usage information\n" \ 492 " -h, --help prints usage information\n" \
185 " -d, --debug enable communication debugging\n" \ 493 " -d, --debug enable communication debugging\n" \
186 " -x, --exit exit when device disconnects\n" \ 494 "\n" \
495 "FILTER OPTIONS:\n" \
496 " -m, --match STRING only print messages that contain STRING\n" \
497 " -t, --trigger STRING start logging when matching STRING\n" \
498 " -T, --untrigger STRING stop logging when matching STRING\n" \
499 " -p, --process PROCESS only print messages from matching process(es)\n" \
500 " -e, --exclude PROCESS print all messages except matching process(es)\n" \
501 " PROCESS is a process name or multiple process names separated by \"|\".\n" \
502 " -q, --quiet set a filter to exclude common noisy processes\n" \
503 " --quiet-list prints the list of processes for --quiet and exits\n" \
504 " -k, --kernel only print kernel messages\n" \
505 " -K, --no-kernel suppress kernel messages\n" \
506 "For filter example usage consult idevicesyslog(1) man page.\n" \
187 "\n" \ 507 "\n" \
188 "Homepage: <" PACKAGE_URL ">\n" 508 "Homepage: <" PACKAGE_URL ">\n"
189 ); 509 );
@@ -191,6 +511,10 @@ static void print_usage(int argc, char **argv, int is_error)
191 511
192int main(int argc, char *argv[]) 512int main(int argc, char *argv[])
193{ 513{
514 int include_filter = 0;
515 int exclude_filter = 0;
516 int include_kernel = 0;
517 int exclude_kernel = 0;
194 int c = 0; 518 int c = 0;
195 const struct option longopts[] = { 519 const struct option longopts[] = {
196 { "debug", no_argument, NULL, 'd' }, 520 { "debug", no_argument, NULL, 'd' },
@@ -198,6 +522,15 @@ int main(int argc, char *argv[])
198 { "udid", required_argument, NULL, 'u' }, 522 { "udid", required_argument, NULL, 'u' },
199 { "network", no_argument, NULL, 'n' }, 523 { "network", no_argument, NULL, 'n' },
200 { "exit", no_argument, NULL, 'x' }, 524 { "exit", no_argument, NULL, 'x' },
525 { "trigger", required_argument, NULL, 't' },
526 { "untrigger", required_argument, NULL, 'T' },
527 { "match", required_argument, NULL, 'm' },
528 { "process", required_argument, NULL, 'p' },
529 { "exclude", required_argument, NULL, 'e' },
530 { "quiet", no_argument, NULL, 'q' },
531 { "kernel", no_argument, NULL, 'k' },
532 { "no-kernel", no_argument, NULL, 'K' },
533 { "quiet-list", no_argument, NULL, 1 },
201 { NULL, 0, NULL, 0} 534 { NULL, 0, NULL, 0}
202 }; 535 };
203 536
@@ -208,7 +541,7 @@ int main(int argc, char *argv[])
208 signal(SIGPIPE, SIG_IGN); 541 signal(SIGPIPE, SIG_IGN);
209#endif 542#endif
210 543
211 while ((c = getopt_long(argc, argv, "dhu:nx", longopts, NULL)) != -1) { 544 while ((c = getopt_long(argc, argv, "dhu:nxt:T:m:e:p:qkK", longopts, NULL)) != -1) {
212 switch (c) { 545 switch (c) {
213 case 'd': 546 case 'd':
214 idevice_set_debug_level(1); 547 idevice_set_debug_level(1);
@@ -225,21 +558,143 @@ int main(int argc, char *argv[])
225 case 'n': 558 case 'n':
226 lookup_opts |= IDEVICE_LOOKUP_PREFER_NETWORK; 559 lookup_opts |= IDEVICE_LOOKUP_PREFER_NETWORK;
227 break; 560 break;
561 case 'q':
562 exclude_filter++;
563 add_filter(QUIET_FILTER);
564 break;
565 case 'p':
566 case 'e':
567 if (c == 'p') {
568 include_filter++;
569 } else if (c == 'e') {
570 exclude_filter++;
571 }
572 if (!*optarg) {
573 fprintf(stderr, "ERROR: filter string must not be empty!\n");
574 print_usage(argc, argv, 1);
575 return 2;
576 }
577 add_filter(optarg);
578 break;
579 case 'm':
580 if (!*optarg) {
581 fprintf(stderr, "ERROR: message filter string must not be empty!\n");
582 print_usage(argc, argv, 1);
583 return 2;
584 } else {
585 char **new_msg_filters = realloc(msg_filters, sizeof(char*) * (num_msg_filters+1));
586 if (!new_msg_filters) {
587 fprintf(stderr, "ERROR: realloc() failed\n");
588 exit(EXIT_FAILURE);
589 }
590 msg_filters = new_msg_filters;
591 msg_filters[num_msg_filters] = strdup(optarg);
592 num_msg_filters++;
593 }
594 break;
595 case 't':
596 if (!*optarg) {
597 fprintf(stderr, "ERROR: trigger filter string must not be empty!\n");
598 print_usage(argc, argv, 1);
599 return 2;
600 } else {
601 char **new_trigger_filters = realloc(trigger_filters, sizeof(char*) * (num_trigger_filters+1));
602 if (!new_trigger_filters) {
603 fprintf(stderr, "ERROR: realloc() failed\n");
604 exit(EXIT_FAILURE);
605 }
606 trigger_filters = new_trigger_filters;
607 trigger_filters[num_trigger_filters] = strdup(optarg);
608 num_trigger_filters++;
609 }
610 break;
611 case 'T':
612 if (!*optarg) {
613 fprintf(stderr, "ERROR: untrigger filter string must not be empty!\n");
614 print_usage(argc, argv, 1);
615 return 2;
616 } else {
617 char **new_untrigger_filters = realloc(untrigger_filters, sizeof(char*) * (num_untrigger_filters+1));
618 if (!new_untrigger_filters) {
619 fprintf(stderr, "ERROR: realloc() failed\n");
620 exit(EXIT_FAILURE);
621 }
622 untrigger_filters = new_untrigger_filters;
623 untrigger_filters[num_untrigger_filters] = strdup(optarg);
624 num_untrigger_filters++;
625 }
626 break;
627 case 'k':
628 include_kernel++;
629 break;
630 case 'K':
631 exclude_kernel++;
632 break;
228 case 'x': 633 case 'x':
229 exit_on_disconnect = 1; 634 exit_on_disconnect = 1;
230 break; 635 break;
231 case 'h': 636 case 'h':
232 print_usage(argc, argv, 0); 637 print_usage(argc, argv, 0);
233 return 0; 638 return 0;
639 case 1: {
640 printf("%s\n", QUIET_FILTER);
641 return 0;
642 }
234 default: 643 default:
235 print_usage(argc, argv, 1); 644 print_usage(argc, argv, 1);
236 return 2; 645 return 2;
237 } 646 }
238 } 647 }
239 648
649 if (include_kernel > 0 && exclude_kernel > 0) {
650 fprintf(stderr, "ERROR: -k and -K cannot be used together.\n");
651 print_usage(argc, argv, 1);
652 return 2;
653 }
654
655 if (include_filter > 0 && exclude_filter > 0) {
656 fprintf(stderr, "ERROR: -p and -e/-q cannot be used together.\n");
657 print_usage(argc, argv, 1);
658 return 2;
659 } else if (include_filter > 0 && exclude_kernel > 0) {
660 fprintf(stderr, "ERROR: -p and -K cannot be used together.\n");
661 print_usage(argc, argv, 1);
662 return 2;
663 }
664
665 if (exclude_filter > 0) {
666 proc_filter_excluding = 1;
667 if (include_kernel) {
668 int i = 0;
669 for (i = 0; i < num_proc_filters; i++) {
670 if (!strcmp(proc_filters[i], "kernel")) {
671 free(proc_filters[i]);
672 proc_filters[i] = NULL;
673 }
674 }
675 } else if (exclude_kernel) {
676 add_filter("kernel");
677 }
678 } else {
679 if (include_kernel) {
680 add_filter("kernel");
681 } else if (exclude_kernel) {
682 proc_filter_excluding = 1;
683 add_filter("kernel");
684 }
685 }
686
687 if (num_untrigger_filters > 0 && num_trigger_filters == 0) {
688 triggered = 1;
689 }
690
240 argc -= optind; 691 argc -= optind;
241 argv += optind; 692 argv += optind;
242 693
694 if (isatty(1)) {
695 use_colors = 1;
696 }
697
243 int num = 0; 698 int num = 0;
244 idevice_info_t *devices = NULL; 699 idevice_info_t *devices = NULL;
245 idevice_get_device_list_extended(&devices, &num); 700 idevice_get_device_list_extended(&devices, &num);
@@ -253,6 +708,9 @@ int main(int argc, char *argv[])
253 } 708 }
254 } 709 }
255 710
711 line_buffer_size = 1024;
712 line = malloc(line_buffer_size);
713
256 idevice_event_subscribe(device_event_cb, NULL); 714 idevice_event_subscribe(device_event_cb, NULL);
257 715
258 while (!quit_flag) { 716 while (!quit_flag) {
@@ -261,6 +719,40 @@ int main(int argc, char *argv[])
261 idevice_event_unsubscribe(); 719 idevice_event_unsubscribe();
262 stop_logging(); 720 stop_logging();
263 721
722 if (num_proc_filters > 0) {
723 int i;
724 for (i = 0; i < num_proc_filters; i++) {
725 free(proc_filters[i]);
726 }
727 free(proc_filters);
728 }
729 if (num_pid_filters > 0) {
730 free(pid_filters);
731 }
732 if (num_msg_filters > 0) {
733 int i;
734 for (i = 0; i < num_msg_filters; i++) {
735 free(msg_filters[i]);
736 }
737 free(msg_filters);
738 }
739 if (num_trigger_filters > 0) {
740 int i;
741 for (i = 0; i < num_trigger_filters; i++) {
742 free(trigger_filters[i]);
743 }
744 free(trigger_filters);
745 }
746 if (num_untrigger_filters > 0) {
747 int i;
748 for (i = 0; i < num_untrigger_filters; i++) {
749 free(untrigger_filters[i]);
750 }
751 free(untrigger_filters);
752 }
753
754 free(line);
755
264 free(udid); 756 free(udid);
265 757
266 return 0; 758 return 0;