This repository has been archived by the owner on Sep 2, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 128
/
cmd_logcat_json.c
242 lines (215 loc) · 7.21 KB
/
cmd_logcat_json.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in
* the LICENSE file in the root directory of this source tree. An
* additional grant of patent rights can be found in the PATENTS file
* in the same directory.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <time.h>
#include "util.h"
#include "autocmd.h"
#include "child.h"
#include "fs.h"
#include "json.h"
// ------------- FROM AOSP ------------
/*
* The maximum size of the log entry payload that can be
* written to the logger. An attempt to write more than
* this amount will result in a truncated log entry.
*/
#define LOGGER_ENTRY_MAX_PAYLOAD 4076
/*
* The userspace structure for version 1 of the logger_entry ABI.
* This structure is returned to userspace by the kernel logger
* driver unless an upgrade to a newer ABI version is requested.
*/
struct logger_entry {
uint16_t len; /* length of the payload */
uint16_t __pad; /* no matter what, we get 2 bytes of padding */
int32_t pid; /* generating process's pid */
int32_t tid; /* generating process's tid */
int32_t sec; /* seconds since Epoch */
int32_t nsec; /* nanoseconds */
char msg[0]; /* the entry's payload */
} __attribute__((__packed__));
/*
* The userspace structure for version 2 of the logger_entry ABI.
* This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
* is called with version==2; or used with the user space log daemon.
*/
struct logger_entry_v2 {
uint16_t len; /* length of the payload */
uint16_t hdr_size; /* sizeof(struct logger_entry_v2) */
int32_t pid; /* generating process's pid */
int32_t tid; /* generating process's tid */
int32_t sec; /* seconds since Epoch */
int32_t nsec; /* nanoseconds */
uint32_t euid; /* effective UID of logger */
char msg[0]; /* the entry's payload */
} __attribute__((__packed__));
struct logger_entry_v3 {
uint16_t len; /* length of the payload */
uint16_t hdr_size; /* sizeof(struct logger_entry_v3) */
int32_t pid; /* generating process's pid */
int32_t tid; /* generating process's tid */
int32_t sec; /* seconds since Epoch */
int32_t nsec; /* nanoseconds */
uint32_t lid; /* log id of the payload */
char msg[0]; /* the entry's payload */
} __attribute__((__packed__));
// ----------- END AOSP -----------
static void
read_all_or_die(int fd, void* buf, size_t sz)
{
size_t nr_read = read_all(fd, buf, sz);
if (nr_read != sz)
die(ENOTBLK, "unexpected EOF from inferior logcat");
}
union logent {
struct logger_entry v1;
struct logger_entry_v2 v2;
struct logger_entry_v3 v3;
};
static const char*
logcat_priority_name(uint8_t priority)
{
switch (priority) {
case 2: return "verbose";
case 3: return "debug";
case 4: return "info";
case 5: return "warn";
case 6: return "error";
case 7: return "fatal";
default: return "?";
}
}
static void
read_and_dump_log_entry(int logcat_fd,
unsigned api_level,
bool gmt,
const char* time_format)
{
SCOPED_RESLIST(rl);
union logent hdr;
union logent* le;
size_t hdrsz;
size_t payloadsz;
read_all_or_die(logcat_fd, &hdr.v1, sizeof (hdr.v1));
if (api_level < 21) {
payloadsz = hdr.v1.len;
hdrsz = sizeof (hdr.v1);
} else {
payloadsz = hdr.v2.len;
hdrsz = hdr.v2.hdr_size;
if (hdrsz < sizeof (hdr.v1))
die(EINVAL, "bogus packet from logcat");
}
le = alloca(hdrsz + payloadsz);
memcpy(&le->v1, &hdr.v1, sizeof (hdr.v1));
read_all_or_die(logcat_fd,
(uint8_t*) le + sizeof (hdr.v1),
hdrsz + payloadsz - sizeof (hdr.v1));
char* payload = (char*) le + hdrsz;
char* payload_end = payload + payloadsz;
struct json_writer* writer = json_writer_create(xstdout);
json_begin_object(writer);
json_begin_field(writer, "pid");
json_emit_i64(writer, le->v1.pid);
json_begin_field(writer, "tid");
json_emit_i64(writer, le->v1.tid);
json_begin_field(writer, "sec");
json_emit_i64(writer, le->v1.sec);
json_begin_field(writer, "nsec");
json_emit_i64(writer, le->v1.nsec);
if (time_format != NULL) {
time_t time = le->v1.sec;
struct tm* tm = (gmt ? gmtime : localtime)(&time);
if (tm != NULL) {
char timebuf[64];
size_t timelen =
strftime(timebuf,
sizeof (timebuf),
time_format,
tm);
json_begin_field(writer, "time");
json_emit_string_n(writer, timebuf, timelen);
}
}
uint8_t priority;
if (payload < payload_end) {
priority = *payload;
payload += 1;
} else {
priority = 0;
}
json_begin_field(writer, "priority");
json_emit_string(writer, logcat_priority_name(priority));
size_t tag_length = strnlen(payload, payload_end - payload);
json_begin_field(writer, "tag");
json_emit_string_n(writer, payload, tag_length);
payload += tag_length;
if (payload < payload_end)
payload += 1;
size_t message_length = strnlen(payload, payload_end - payload);
json_begin_field(writer, "message");
json_emit_string_n(writer, payload, message_length);
json_end_object(writer);
xputc('\n', xstdout);
xflush(xstdout);
}
int
logcat_json_main(const struct cmd_logcat_json_info* info)
{
struct cmd_shell_info shcmdi = {
.adb = info->adb,
.transport = info->transport,
.user = info->user,
.command = "getprop ro.build.version.sdk&&exec logcat -B"
};
struct strlist* args = strlist_new();
strlist_append(args, orig_argv0);
strlist_append(args, "shell");
strlist_xfer(args, make_args_cmd_shell(CMD_ARG_FORWARDED, &shcmdi));
struct child_start_info csi = {
.io[STDIN_FILENO] = CHILD_IO_DEV_NULL,
.io[STDOUT_FILENO] = CHILD_IO_PIPE,
.io[STDERR_FILENO] = CHILD_IO_RECORD,
.exename = my_exe(),
.argv = strlist_to_argv(args),
};
struct child* captive_logcat = child_start(&csi);
install_child_error_converter(captive_logcat);
int logcat_fd = captive_logcat->fd[1]->fd;
unsigned api_level = 0;
for (;;) {
char c;
if (read_all(logcat_fd, &c, 1) < 1)
die(ECOMM, "invalid API level");
if ('0' <= c && c <= '9')
api_level = api_level * 10 + (c - '0');
else if (c == '\n')
break;
else
die(ECOMM, "invalid API level");
}
if (api_level == 0)
die(ECOMM, "invalid API level");
const char* time_format = "%a, %d %b %Y %H:%M:%S";
if (info->logcat_json.time_format)
time_format = info->logcat_json.time_format;
bool gmt = info->logcat_json.gmt;
for (;;) {
read_and_dump_log_entry(
logcat_fd,
api_level,
gmt,
time_format);
}
}