blob: af52528f8d0b126ee7f87b05c14614f144ba3f9e [file] [log] [blame]
Mark Salyzyncf4aa032013-11-22 07:54:30 -08001/*
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07002**
Mark Salyzyn40b21552013-12-18 12:59:01 -08003** Copyright 2006-2014, The Android Open Source Project
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07004**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define _GNU_SOURCE /* for asprintf */
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -080019#ifndef __MINGW32__
20#define HAVE_STRSEP
21#endif
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070022
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -080023//#ifndef __MINGW32__
24//#include <arpa/inet.h>
25//#endif
Mark Salyzyna04464a2014-04-30 08:50:53 -070026#include <assert.h>
27#include <ctype.h>
28#include <errno.h>
Mark Salyzyn4fd05072016-10-18 11:30:11 -070029#include <inttypes.h>
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -080030#ifndef __MINGW32__
William Roberts8a5b9ca2016-04-08 12:13:17 -070031#include <pwd.h>
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -080032#endif
Pierre Zurekead88fc2010-10-17 22:39:37 +020033#include <stdbool.h>
Mark Salyzyna04464a2014-04-30 08:50:53 -070034#include <stdint.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
Pierre Zurekead88fc2010-10-17 22:39:37 +020038#include <sys/param.h>
William Roberts8a5b9ca2016-04-08 12:13:17 -070039#include <sys/types.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070040
Mark Salyzyn4cbed022015-08-31 15:53:41 -070041#include <cutils/list.h>
Mark Salyzynaeaaf812016-09-30 13:30:33 -070042#include <log/log.h>
Colin Cross9227bd32013-07-23 16:59:20 -070043#include <log/logprint.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070044
Mark Salyzyn018a96d2016-03-01 13:45:42 -080045#include "log_portability.h"
Mark Salyzynbe1d3c22016-03-10 08:25:33 -080046
Mark Salyzyn4cbed022015-08-31 15:53:41 -070047#define MS_PER_NSEC 1000000
48#define US_PER_NSEC 1000
49
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -080050#ifndef MIN
51#define MIN(a,b) (((a) < (b)) ? (a) : (b))
52#endif
53
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070054typedef struct FilterInfo_t {
55 char *mTag;
56 android_LogPriority mPri;
57 struct FilterInfo_t *p_next;
58} FilterInfo;
59
60struct AndroidLogFormat_t {
61 android_LogPriority global_pri;
62 FilterInfo *filters;
63 AndroidLogPrintFormat format;
Pierre Zurekead88fc2010-10-17 22:39:37 +020064 bool colored_output;
Mark Salyzyne1f20042015-05-06 08:40:40 -070065 bool usec_time_output;
Mark Salyzyn9b4d7e12017-01-30 09:16:09 -080066 bool nsec_time_output;
Mark Salyzynb932b2f2015-05-15 09:01:58 -070067 bool printable_output;
Mark Salyzynf28f6a92015-08-31 08:01:33 -070068 bool year_output;
69 bool zone_output;
Mark Salyzyn4cbed022015-08-31 15:53:41 -070070 bool epoch_output;
71 bool monotonic_output;
Mark Salyzyn90e7af32015-12-07 16:52:42 -080072 bool uid_output;
Mark Salyzyn4fd05072016-10-18 11:30:11 -070073 bool descriptive_output;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070074};
75
Pierre Zurekead88fc2010-10-17 22:39:37 +020076/*
Mark Salyzyn4fd05072016-10-18 11:30:11 -070077 * API issues prevent us from exposing "descriptive" in AndroidLogFormat_t
78 * during android_log_processBinaryLogBuffer(), so we break layering.
79 */
80static bool descriptive_output = false;
81
82/*
Pierre Zurekead88fc2010-10-17 22:39:37 +020083 * gnome-terminal color tags
84 * See http://misc.flogisoft.com/bash/tip_colors_and_formatting
85 * for ideas on how to set the forground color of the text for xterm.
86 * The color manipulation character stream is defined as:
87 * ESC [ 3 8 ; 5 ; <color#> m
88 */
89#define ANDROID_COLOR_BLUE 75
90#define ANDROID_COLOR_DEFAULT 231
91#define ANDROID_COLOR_GREEN 40
92#define ANDROID_COLOR_ORANGE 166
93#define ANDROID_COLOR_RED 196
94#define ANDROID_COLOR_YELLOW 226
95
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070096static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri)
97{
98 FilterInfo *p_ret;
99
100 p_ret = (FilterInfo *)calloc(1, sizeof(FilterInfo));
101 p_ret->mTag = strdup(tag);
102 p_ret->mPri = pri;
103
104 return p_ret;
105}
106
Mark Salyzyna04464a2014-04-30 08:50:53 -0700107/* balance to above, filterinfo_free left unimplemented */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700108
109/*
110 * Note: also accepts 0-9 priorities
111 * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
112 */
113static android_LogPriority filterCharToPri (char c)
114{
115 android_LogPriority pri;
116
117 c = tolower(c);
118
119 if (c >= '0' && c <= '9') {
120 if (c >= ('0'+ANDROID_LOG_SILENT)) {
121 pri = ANDROID_LOG_VERBOSE;
122 } else {
123 pri = (android_LogPriority)(c - '0');
124 }
125 } else if (c == 'v') {
126 pri = ANDROID_LOG_VERBOSE;
127 } else if (c == 'd') {
128 pri = ANDROID_LOG_DEBUG;
129 } else if (c == 'i') {
130 pri = ANDROID_LOG_INFO;
131 } else if (c == 'w') {
132 pri = ANDROID_LOG_WARN;
133 } else if (c == 'e') {
134 pri = ANDROID_LOG_ERROR;
135 } else if (c == 'f') {
136 pri = ANDROID_LOG_FATAL;
137 } else if (c == 's') {
138 pri = ANDROID_LOG_SILENT;
139 } else if (c == '*') {
140 pri = ANDROID_LOG_DEFAULT;
141 } else {
142 pri = ANDROID_LOG_UNKNOWN;
143 }
144
145 return pri;
146}
147
148static char filterPriToChar (android_LogPriority pri)
149{
150 switch (pri) {
151 case ANDROID_LOG_VERBOSE: return 'V';
152 case ANDROID_LOG_DEBUG: return 'D';
153 case ANDROID_LOG_INFO: return 'I';
154 case ANDROID_LOG_WARN: return 'W';
155 case ANDROID_LOG_ERROR: return 'E';
156 case ANDROID_LOG_FATAL: return 'F';
157 case ANDROID_LOG_SILENT: return 'S';
158
159 case ANDROID_LOG_DEFAULT:
160 case ANDROID_LOG_UNKNOWN:
161 default: return '?';
162 }
163}
164
Pierre Zurekead88fc2010-10-17 22:39:37 +0200165static int colorFromPri (android_LogPriority pri)
166{
167 switch (pri) {
168 case ANDROID_LOG_VERBOSE: return ANDROID_COLOR_DEFAULT;
169 case ANDROID_LOG_DEBUG: return ANDROID_COLOR_BLUE;
170 case ANDROID_LOG_INFO: return ANDROID_COLOR_GREEN;
171 case ANDROID_LOG_WARN: return ANDROID_COLOR_ORANGE;
172 case ANDROID_LOG_ERROR: return ANDROID_COLOR_RED;
173 case ANDROID_LOG_FATAL: return ANDROID_COLOR_RED;
174 case ANDROID_LOG_SILENT: return ANDROID_COLOR_DEFAULT;
175
176 case ANDROID_LOG_DEFAULT:
177 case ANDROID_LOG_UNKNOWN:
178 default: return ANDROID_COLOR_DEFAULT;
179 }
180}
181
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700182static android_LogPriority filterPriForTag(
183 AndroidLogFormat *p_format, const char *tag)
184{
185 FilterInfo *p_curFilter;
186
187 for (p_curFilter = p_format->filters
188 ; p_curFilter != NULL
189 ; p_curFilter = p_curFilter->p_next
190 ) {
191 if (0 == strcmp(tag, p_curFilter->mTag)) {
192 if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
193 return p_format->global_pri;
194 } else {
195 return p_curFilter->mPri;
196 }
197 }
198 }
199
200 return p_format->global_pri;
201}
202
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700203/**
204 * returns 1 if this log line should be printed based on its priority
205 * and tag, and 0 if it should not
206 */
Mark Salyzynbe1d3c22016-03-10 08:25:33 -0800207LIBLOG_ABI_PUBLIC int android_log_shouldPrintLine (
208 AndroidLogFormat *p_format,
209 const char *tag,
210 android_LogPriority pri)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700211{
212 return pri >= filterPriForTag(p_format, tag);
213}
214
Mark Salyzynbe1d3c22016-03-10 08:25:33 -0800215LIBLOG_ABI_PUBLIC AndroidLogFormat *android_log_format_new()
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700216{
217 AndroidLogFormat *p_ret;
218
219 p_ret = calloc(1, sizeof(AndroidLogFormat));
220
221 p_ret->global_pri = ANDROID_LOG_VERBOSE;
222 p_ret->format = FORMAT_BRIEF;
Pierre Zurekead88fc2010-10-17 22:39:37 +0200223 p_ret->colored_output = false;
Mark Salyzyne1f20042015-05-06 08:40:40 -0700224 p_ret->usec_time_output = false;
Mark Salyzyn9b4d7e12017-01-30 09:16:09 -0800225 p_ret->nsec_time_output = false;
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700226 p_ret->printable_output = false;
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700227 p_ret->year_output = false;
228 p_ret->zone_output = false;
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700229 p_ret->epoch_output = false;
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -0800230#ifdef __ANDROID__
Mark Salyzynba7a9a02015-12-01 15:57:25 -0800231 p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -0800232#else
233 p_ret->monotonic_output = false;
234#endif
Mark Salyzyn90e7af32015-12-07 16:52:42 -0800235 p_ret->uid_output = false;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700236 p_ret->descriptive_output = false;
237 descriptive_output = false;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700238
239 return p_ret;
240}
241
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700242static list_declare(convertHead);
243
Mark Salyzynbe1d3c22016-03-10 08:25:33 -0800244LIBLOG_ABI_PUBLIC void android_log_format_free(AndroidLogFormat *p_format)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700245{
246 FilterInfo *p_info, *p_info_old;
247
248 p_info = p_format->filters;
249
250 while (p_info != NULL) {
251 p_info_old = p_info;
252 p_info = p_info->p_next;
253
254 free(p_info_old);
255 }
256
257 free(p_format);
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700258
259 /* Free conversion resource, can always be reconstructed */
260 while (!list_empty(&convertHead)) {
261 struct listnode *node = list_head(&convertHead);
262 list_remove(node);
263 free(node);
264 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700265}
266
Mark Salyzynbe1d3c22016-03-10 08:25:33 -0800267LIBLOG_ABI_PUBLIC int android_log_setPrintFormat(
268 AndroidLogFormat *p_format,
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700269 AndroidLogPrintFormat format)
270{
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700271 switch (format) {
272 case FORMAT_MODIFIER_COLOR:
Pierre Zurekead88fc2010-10-17 22:39:37 +0200273 p_format->colored_output = true;
Mark Salyzyne1f20042015-05-06 08:40:40 -0700274 return 0;
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700275 case FORMAT_MODIFIER_TIME_USEC:
Mark Salyzyne1f20042015-05-06 08:40:40 -0700276 p_format->usec_time_output = true;
277 return 0;
Mark Salyzyn9b4d7e12017-01-30 09:16:09 -0800278 case FORMAT_MODIFIER_TIME_NSEC:
279 p_format->nsec_time_output = true;
280 return 0;
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700281 case FORMAT_MODIFIER_PRINTABLE:
282 p_format->printable_output = true;
283 return 0;
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700284 case FORMAT_MODIFIER_YEAR:
285 p_format->year_output = true;
286 return 0;
287 case FORMAT_MODIFIER_ZONE:
288 p_format->zone_output = !p_format->zone_output;
289 return 0;
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700290 case FORMAT_MODIFIER_EPOCH:
291 p_format->epoch_output = true;
292 return 0;
293 case FORMAT_MODIFIER_MONOTONIC:
294 p_format->monotonic_output = true;
295 return 0;
Mark Salyzyn90e7af32015-12-07 16:52:42 -0800296 case FORMAT_MODIFIER_UID:
297 p_format->uid_output = true;
298 return 0;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700299 case FORMAT_MODIFIER_DESCRIPT:
300 p_format->descriptive_output = true;
301 descriptive_output = true;
302 return 0;
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700303 default:
304 break;
Mark Salyzyne1f20042015-05-06 08:40:40 -0700305 }
306 p_format->format = format;
307 return 1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700308}
309
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700310static const char tz[] = "TZ";
311static const char utc[] = "UTC";
312
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700313/**
314 * Returns FORMAT_OFF on invalid string
315 */
Mark Salyzynbe1d3c22016-03-10 08:25:33 -0800316LIBLOG_ABI_PUBLIC AndroidLogPrintFormat android_log_formatFromString(
317 const char * formatString)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700318{
319 static AndroidLogPrintFormat format;
320
321 if (strcmp(formatString, "brief") == 0) format = FORMAT_BRIEF;
322 else if (strcmp(formatString, "process") == 0) format = FORMAT_PROCESS;
323 else if (strcmp(formatString, "tag") == 0) format = FORMAT_TAG;
324 else if (strcmp(formatString, "thread") == 0) format = FORMAT_THREAD;
325 else if (strcmp(formatString, "raw") == 0) format = FORMAT_RAW;
326 else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
327 else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
328 else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
Mark Salyzyne1f20042015-05-06 08:40:40 -0700329 else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700330 else if (strcmp(formatString, "colour") == 0) format = FORMAT_MODIFIER_COLOR;
Mark Salyzyne1f20042015-05-06 08:40:40 -0700331 else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
Mark Salyzyn9b4d7e12017-01-30 09:16:09 -0800332 else if (strcmp(formatString, "nsec") == 0) format = FORMAT_MODIFIER_TIME_NSEC;
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700333 else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700334 else if (strcmp(formatString, "year") == 0) format = FORMAT_MODIFIER_YEAR;
335 else if (strcmp(formatString, "zone") == 0) format = FORMAT_MODIFIER_ZONE;
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700336 else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH;
337 else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
Mark Salyzyn90e7af32015-12-07 16:52:42 -0800338 else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700339 else if (strcmp(formatString, "descriptive") == 0) format = FORMAT_MODIFIER_DESCRIPT;
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -0800340#ifndef __MINGW32__
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700341 else {
342 extern char *tzname[2];
343 static const char gmt[] = "GMT";
344 char *cp = getenv(tz);
345 if (cp) {
346 cp = strdup(cp);
347 }
348 setenv(tz, formatString, 1);
349 /*
350 * Run tzset here to determine if the timezone is legitimate. If the
351 * zone is GMT, check if that is what was asked for, if not then
352 * did not match any on the system; report an error to caller.
353 */
354 tzset();
355 if (!tzname[0]
356 || ((!strcmp(tzname[0], utc)
357 || !strcmp(tzname[0], gmt)) /* error? */
358 && strcasecmp(formatString, utc)
359 && strcasecmp(formatString, gmt))) { /* ok */
360 if (cp) {
361 setenv(tz, cp, 1);
362 } else {
363 unsetenv(tz);
364 }
365 tzset();
366 format = FORMAT_OFF;
367 } else {
368 format = FORMAT_MODIFIER_ZONE;
369 }
370 free(cp);
371 }
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -0800372#endif
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700373
374 return format;
375}
376
377/**
378 * filterExpression: a single filter expression
379 * eg "AT:d"
380 *
381 * returns 0 on success and -1 on invalid expression
382 *
383 * Assumes single threaded execution
384 */
385
Mark Salyzynbe1d3c22016-03-10 08:25:33 -0800386LIBLOG_ABI_PUBLIC int android_log_addFilterRule(
387 AndroidLogFormat *p_format,
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700388 const char *filterExpression)
389{
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700390 size_t tagNameLength;
391 android_LogPriority pri = ANDROID_LOG_DEFAULT;
392
393 tagNameLength = strcspn(filterExpression, ":");
394
395 if (tagNameLength == 0) {
396 goto error;
397 }
398
399 if(filterExpression[tagNameLength] == ':') {
400 pri = filterCharToPri(filterExpression[tagNameLength+1]);
401
402 if (pri == ANDROID_LOG_UNKNOWN) {
403 goto error;
404 }
405 }
406
407 if(0 == strncmp("*", filterExpression, tagNameLength)) {
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700408 /*
409 * This filter expression refers to the global filter
410 * The default level for this is DEBUG if the priority
411 * is unspecified
412 */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700413 if (pri == ANDROID_LOG_DEFAULT) {
414 pri = ANDROID_LOG_DEBUG;
415 }
416
417 p_format->global_pri = pri;
418 } else {
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700419 /*
420 * for filter expressions that don't refer to the global
421 * filter, the default is verbose if the priority is unspecified
422 */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700423 if (pri == ANDROID_LOG_DEFAULT) {
424 pri = ANDROID_LOG_VERBOSE;
425 }
426
427 char *tagName;
428
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700429/*
430 * Presently HAVE_STRNDUP is never defined, so the second case is always taken
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -0800431 * Darwin doesn't have strndup, everything else does
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700432 */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700433#ifdef HAVE_STRNDUP
434 tagName = strndup(filterExpression, tagNameLength);
435#else
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700436 /* a few extra bytes copied... */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700437 tagName = strdup(filterExpression);
438 tagName[tagNameLength] = '\0';
439#endif /*HAVE_STRNDUP*/
440
441 FilterInfo *p_fi = filterinfo_new(tagName, pri);
442 free(tagName);
443
444 p_fi->p_next = p_format->filters;
445 p_format->filters = p_fi;
446 }
447
448 return 0;
449error:
450 return -1;
451}
452
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -0800453#ifndef HAVE_STRSEP
454/* KISS replacement helper for below */
455static char* strsep(char** stringp, const char* delim)
456{
457 char* token;
458 char* ret = *stringp;
459
460 if (!ret || !*ret) {
461 return NULL;
462 }
463 token = strpbrk(ret, delim);
464 if (token) {
465 *token = '\0';
466 ++token;
467 } else {
468 token = ret + strlen(ret);
469 }
470 *stringp = token;
471 return ret;
472}
473#endif
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700474
475/**
476 * filterString: a comma/whitespace-separated set of filter expressions
477 *
478 * eg "AT:d *:i"
479 *
480 * returns 0 on success and -1 on invalid expression
481 *
482 * Assumes single threaded execution
483 *
484 */
Mark Salyzynbe1d3c22016-03-10 08:25:33 -0800485LIBLOG_ABI_PUBLIC int android_log_addFilterString(
486 AndroidLogFormat *p_format,
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700487 const char *filterString)
488{
489 char *filterStringCopy = strdup (filterString);
490 char *p_cur = filterStringCopy;
491 char *p_ret;
492 int err;
493
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700494 /* Yes, I'm using strsep */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700495 while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700496 /* ignore whitespace-only entries */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700497 if(p_ret[0] != '\0') {
498 err = android_log_addFilterRule(p_format, p_ret);
499
500 if (err < 0) {
501 goto error;
502 }
503 }
504 }
505
506 free (filterStringCopy);
507 return 0;
508error:
509 free (filterStringCopy);
510 return -1;
511}
512
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700513/**
514 * Splits a wire-format buffer into an AndroidLogEntry
515 * entry allocated by caller. Pointers will point directly into buf
516 *
517 * Returns 0 on success and -1 on invalid wire format (entry will be
518 * in unspecified state)
519 */
Mark Salyzynbe1d3c22016-03-10 08:25:33 -0800520LIBLOG_ABI_PUBLIC int android_log_processLogBuffer(
521 struct logger_entry *buf,
522 AndroidLogEntry *entry)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700523{
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700524 entry->tv_sec = buf->sec;
525 entry->tv_nsec = buf->nsec;
Mark Salyzyn90e7af32015-12-07 16:52:42 -0800526 entry->uid = -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700527 entry->pid = buf->pid;
528 entry->tid = buf->tid;
Kenny Root4bf3c022011-09-30 17:10:14 -0700529
530 /*
531 * format: <priority:1><tag:N>\0<message:N>\0
532 *
533 * tag str
Nick Kraleviche1ede152011-10-18 15:23:33 -0700534 * starts at buf->msg+1
Kenny Root4bf3c022011-09-30 17:10:14 -0700535 * msg
Nick Kraleviche1ede152011-10-18 15:23:33 -0700536 * starts at buf->msg+1+len(tag)+1
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700537 *
538 * The message may have been truncated by the kernel log driver.
539 * When that happens, we must null-terminate the message ourselves.
Kenny Root4bf3c022011-09-30 17:10:14 -0700540 */
Nick Kraleviche1ede152011-10-18 15:23:33 -0700541 if (buf->len < 3) {
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700542 /*
543 * An well-formed entry must consist of at least a priority
544 * and two null characters
545 */
Nick Kraleviche1ede152011-10-18 15:23:33 -0700546 fprintf(stderr, "+++ LOG: entry too small\n");
Kenny Root4bf3c022011-09-30 17:10:14 -0700547 return -1;
548 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700549
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700550 int msgStart = -1;
551 int msgEnd = -1;
552
Nick Kraleviche1ede152011-10-18 15:23:33 -0700553 int i;
Mark Salyzyn40b21552013-12-18 12:59:01 -0800554 char *msg = buf->msg;
555 struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
556 if (buf2->hdr_size) {
Mark Salyzyn305374c2016-08-18 14:59:41 -0700557 if ((buf2->hdr_size < sizeof(((struct log_msg *)NULL)->entry_v1)) ||
558 (buf2->hdr_size > sizeof(((struct log_msg *)NULL)->entry))) {
559 fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
560 return -1;
561 }
Mark Salyzyn40b21552013-12-18 12:59:01 -0800562 msg = ((char *)buf2) + buf2->hdr_size;
Mark Salyzyn90e7af32015-12-07 16:52:42 -0800563 if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
564 entry->uid = ((struct logger_entry_v4 *)buf)->uid;
565 }
Mark Salyzyn40b21552013-12-18 12:59:01 -0800566 }
Nick Kraleviche1ede152011-10-18 15:23:33 -0700567 for (i = 1; i < buf->len; i++) {
Mark Salyzyn40b21552013-12-18 12:59:01 -0800568 if (msg[i] == '\0') {
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700569 if (msgStart == -1) {
570 msgStart = i + 1;
571 } else {
572 msgEnd = i;
573 break;
574 }
Nick Kraleviche1ede152011-10-18 15:23:33 -0700575 }
576 }
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700577
578 if (msgStart == -1) {
Mark Salyzyn083c5342016-03-21 09:45:34 -0700579 /* +++ LOG: malformed log message, DYB */
580 for (i = 1; i < buf->len; i++) {
581 /* odd characters in tag? */
582 if ((msg[i] <= ' ') || (msg[i] == ':') || (msg[i] >= 0x7f)) {
583 msg[i] = '\0';
584 msgStart = i + 1;
585 break;
586 }
587 }
588 if (msgStart == -1) {
589 msgStart = buf->len - 1; /* All tag, no message, print truncates */
590 }
Nick Kralevich63f4a842011-10-17 10:45:03 -0700591 }
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700592 if (msgEnd == -1) {
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700593 /* incoming message not null-terminated; force it */
Mark Salyzynd7bcf402015-12-04 09:24:15 -0800594 msgEnd = buf->len - 1; /* may result in msgEnd < msgStart */
Mark Salyzyn40b21552013-12-18 12:59:01 -0800595 msg[msgEnd] = '\0';
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700596 }
597
Mark Salyzyn40b21552013-12-18 12:59:01 -0800598 entry->priority = msg[0];
599 entry->tag = msg + 1;
Mark Salyzyn807e40e2016-09-22 09:56:51 -0700600 entry->tagLen = msgStart - 1;
Mark Salyzyn40b21552013-12-18 12:59:01 -0800601 entry->message = msg + msgStart;
Mark Salyzynd7bcf402015-12-04 09:24:15 -0800602 entry->messageLen = (msgEnd < msgStart) ? 0 : (msgEnd - msgStart);
Nick Kralevich63f4a842011-10-17 10:45:03 -0700603
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700604 return 0;
605}
606
607/*
Mark Salyzyn8470dad2015-03-06 20:42:57 +0000608 * Extract a 4-byte value from a byte stream.
609 */
610static inline uint32_t get4LE(const uint8_t* src)
611{
612 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
613}
614
615/*
616 * Extract an 8-byte value from a byte stream.
617 */
618static inline uint64_t get8LE(const uint8_t* src)
619{
620 uint32_t low, high;
621
622 low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
623 high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
Jeff Brown44193d92015-04-28 12:47:02 -0700624 return ((uint64_t) high << 32) | (uint64_t) low;
Mark Salyzyn8470dad2015-03-06 20:42:57 +0000625}
626
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700627static bool findChar(const char** cp, size_t* len, int c) {
Mark Salyzyn8dcd94b2016-11-07 13:54:42 -0800628 while ((*len) && isspace(*(*cp))) {
629 ++(*cp);
630 --(*len);
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700631 }
632 if (c == INT_MAX) return *len;
Mark Salyzyn8dcd94b2016-11-07 13:54:42 -0800633 if ((*len) && (*(*cp) == c)) {
634 ++(*cp);
635 --(*len);
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700636 return true;
637 }
638 return false;
639}
Mark Salyzyn8470dad2015-03-06 20:42:57 +0000640
641/*
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700642 * Recursively convert binary log data to printable form.
643 *
644 * This needs to be recursive because you can have lists of lists.
645 *
646 * If we run out of room, we stop processing immediately. It's important
647 * for us to check for space on every output element to avoid producing
648 * garbled output.
649 *
650 * Returns 0 on success, 1 on buffer full, -1 on failure.
651 */
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700652enum objectType {
653 TYPE_OBJECTS = '1',
654 TYPE_BYTES = '2',
655 TYPE_MILLISECONDS = '3',
656 TYPE_ALLOCATIONS = '4',
657 TYPE_ID = '5',
658 TYPE_PERCENT = '6'
659};
660
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700661static int android_log_printBinaryEvent(const unsigned char** pEventData,
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700662 size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen,
663 const char** fmtStr, size_t* fmtLen)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700664{
665 const unsigned char* eventData = *pEventData;
666 size_t eventDataLen = *pEventDataLen;
667 char* outBuf = *pOutBuf;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700668 char* outBufSave = outBuf;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700669 size_t outBufLen = *pOutBufLen;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700670 size_t outBufLenSave = outBufLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700671 unsigned char type;
672 size_t outCount;
673 int result = 0;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700674 const char* cp;
675 size_t len;
676 int64_t lval;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700677
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800678 if (eventDataLen < 1) return -1;
679
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700680 type = *eventData++;
681 eventDataLen--;
682
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700683 cp = NULL;
684 len = 0;
685 if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
686 cp = *fmtStr;
687 len = *fmtLen;
688 }
689 /*
690 * event.logtag format specification:
691 *
692 * Optionally, after the tag names can be put a description for the value(s)
693 * of the tag. Description are in the format
694 * (<name>|data type[|data unit])
695 * Multiple values are separated by commas.
696 *
697 * The data type is a number from the following values:
698 * 1: int
699 * 2: long
700 * 3: string
701 * 4: list
702 * 5: float
703 *
704 * The data unit is a number taken from the following list:
705 * 1: Number of objects
706 * 2: Number of bytes
707 * 3: Number of milliseconds
708 * 4: Number of allocations
709 * 5: Id
710 * 6: Percent
711 * Default value for data of type int/long is 2 (bytes).
712 */
713 if (!cp || !findChar(&cp, &len, '(')) {
714 len = 0;
715 } else {
716 char* outBufLastSpace = NULL;
717
718 findChar(&cp, &len, INT_MAX);
719 while (len && *cp && (*cp != '|') && (*cp != ')')) {
720 if (outBufLen <= 0) {
721 /* halt output */
722 goto no_room;
723 }
724 outBufLastSpace = isspace(*cp) ? outBuf : NULL;
725 *outBuf = *cp;
726 ++outBuf;
727 ++cp;
728 --outBufLen;
729 --len;
730 }
731 if (outBufLastSpace) {
732 outBufLen += outBuf - outBufLastSpace;
733 outBuf = outBufLastSpace;
734 }
735 if (outBufLen <= 0) {
736 /* halt output */
737 goto no_room;
738 }
739 if (outBufSave != outBuf) {
740 *outBuf = '=';
741 ++outBuf;
742 --outBufLen;
743 }
744
745 if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
746 static const unsigned char typeTable[] = {
747 EVENT_TYPE_INT,
748 EVENT_TYPE_LONG,
749 EVENT_TYPE_STRING,
750 EVENT_TYPE_LIST,
751 EVENT_TYPE_FLOAT
752 };
753
754 if ((*cp >= '1') &&
755 (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
756 (type != typeTable[(size_t)(*cp - '1')])) len = 0;
757
758 if (len) {
759 ++cp;
760 --len;
761 } else {
762 /* reset the format */
763 outBuf = outBufSave;
764 outBufLen = outBufLenSave;
765 }
766 }
767 }
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -0800768 outCount = 0;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700769 lval = 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700770 switch (type) {
771 case EVENT_TYPE_INT:
772 /* 32-bit signed int */
773 {
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700774 int32_t ival;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700775
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800776 if (eventDataLen < 4) return -1;
Mark Salyzyn8470dad2015-03-06 20:42:57 +0000777 ival = get4LE(eventData);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700778 eventData += 4;
779 eventDataLen -= 4;
780
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700781 lval = ival;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700782 }
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700783 goto pr_lval;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700784 case EVENT_TYPE_LONG:
785 /* 64-bit signed long */
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800786 if (eventDataLen < 8) return -1;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700787 lval = get8LE(eventData);
788 eventData += 8;
789 eventDataLen -= 8;
790 pr_lval:
791 outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
792 if (outCount < outBufLen) {
793 outBuf += outCount;
794 outBufLen -= outCount;
795 } else {
796 /* halt output */
797 goto no_room;
Jeff Brown44193d92015-04-28 12:47:02 -0700798 }
799 break;
800 case EVENT_TYPE_FLOAT:
801 /* float */
802 {
803 uint32_t ival;
804 float fval;
805
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800806 if (eventDataLen < 4) return -1;
Jeff Brown44193d92015-04-28 12:47:02 -0700807 ival = get4LE(eventData);
808 fval = *(float*)&ival;
809 eventData += 4;
810 eventDataLen -= 4;
811
812 outCount = snprintf(outBuf, outBufLen, "%f", fval);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700813 if (outCount < outBufLen) {
814 outBuf += outCount;
815 outBufLen -= outCount;
816 } else {
817 /* halt output */
818 goto no_room;
819 }
820 }
821 break;
822 case EVENT_TYPE_STRING:
823 /* UTF-8 chars, not NULL-terminated */
824 {
825 unsigned int strLen;
826
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800827 if (eventDataLen < 4) return -1;
Mark Salyzyn8470dad2015-03-06 20:42:57 +0000828 strLen = get4LE(eventData);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700829 eventData += 4;
830 eventDataLen -= 4;
831
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800832 if (eventDataLen < strLen) return -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700833
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700834 if (cp && (strLen == 0)) {
835 /* reset the format if no content */
836 outBuf = outBufSave;
837 outBufLen = outBufLenSave;
838 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700839 if (strLen < outBufLen) {
840 memcpy(outBuf, eventData, strLen);
841 outBuf += strLen;
842 outBufLen -= strLen;
843 } else if (outBufLen > 0) {
844 /* copy what we can */
845 memcpy(outBuf, eventData, outBufLen);
846 outBuf += outBufLen;
847 outBufLen -= outBufLen;
848 goto no_room;
849 }
850 eventData += strLen;
851 eventDataLen -= strLen;
852 break;
853 }
854 case EVENT_TYPE_LIST:
855 /* N items, all different types */
856 {
857 unsigned char count;
858 int i;
859
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800860 if (eventDataLen < 1) return -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700861
862 count = *eventData++;
863 eventDataLen--;
864
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800865 if (outBufLen <= 0) goto no_room;
866
867 *outBuf++ = '[';
868 outBufLen--;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700869
870 for (i = 0; i < count; i++) {
871 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700872 &outBuf, &outBufLen, fmtStr, fmtLen);
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800873 if (result != 0) goto bail;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700874
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800875 if (i < (count - 1)) {
876 if (outBufLen <= 0) goto no_room;
877 *outBuf++ = ',';
878 outBufLen--;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700879 }
880 }
881
Mark Salyzyn1a57ae32016-11-11 14:41:30 -0800882 if (outBufLen <= 0) goto no_room;
883
884 *outBuf++ = ']';
885 outBufLen--;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700886 }
887 break;
888 default:
889 fprintf(stderr, "Unknown binary event type %d\n", type);
890 return -1;
891 }
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700892 if (cp && len) {
893 if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
894 switch (*cp) {
895 case TYPE_OBJECTS:
896 outCount = 0;
897 /* outCount = snprintf(outBuf, outBufLen, " objects"); */
898 break;
899 case TYPE_BYTES:
900 if ((lval != 0) && ((lval % 1024) == 0)) {
901 /* repaint with multiplier */
902 static const char suffixTable[] = { 'K', 'M', 'G', 'T' };
903 size_t idx = 0;
904 outBuf -= outCount;
905 outBufLen += outCount;
906 do {
907 lval /= 1024;
908 if ((lval % 1024) != 0) break;
909 } while (++idx < ((sizeof(suffixTable) /
910 sizeof(suffixTable[0])) - 1));
911 outCount = snprintf(outBuf, outBufLen,
912 "%" PRId64 "%cB",
913 lval, suffixTable[idx]);
914 } else {
915 outCount = snprintf(outBuf, outBufLen, "B");
916 }
917 break;
918 case TYPE_MILLISECONDS:
919 if (((lval <= -1000) || (1000 <= lval)) &&
920 (outBufLen || (outBuf[-1] == '0'))) {
921 /* repaint as (fractional) seconds, possibly saving space */
922 if (outBufLen) outBuf[0] = outBuf[-1];
923 outBuf[-1] = outBuf[-2];
924 outBuf[-2] = outBuf[-3];
925 outBuf[-3] = '.';
926 while ((outBufLen == 0) || (*outBuf == '0')) {
927 --outBuf;
928 ++outBufLen;
929 }
930 if (*outBuf != '.') {
931 ++outBuf;
932 --outBufLen;
933 }
934 outCount = snprintf(outBuf, outBufLen, "s");
935 } else {
936 outCount = snprintf(outBuf, outBufLen, "ms");
937 }
938 break;
939 case TYPE_ALLOCATIONS:
940 outCount = 0;
941 /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
942 break;
943 case TYPE_ID:
944 outCount = 0;
945 break;
946 case TYPE_PERCENT:
947 outCount = snprintf(outBuf, outBufLen, "%%");
948 break;
949 default: /* ? */
950 outCount = 0;
951 break;
952 }
953 ++cp;
954 --len;
955 if (outCount < outBufLen) {
956 outBuf += outCount;
957 outBufLen -= outCount;
958 } else if (outCount) {
959 /* halt output */
960 goto no_room;
961 }
962 }
963 if (!findChar(&cp, &len, ')')) len = 0;
964 if (!findChar(&cp, &len, ',')) len = 0;
965 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700966
967bail:
968 *pEventData = eventData;
969 *pEventDataLen = eventDataLen;
970 *pOutBuf = outBuf;
971 *pOutBufLen = outBufLen;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700972 if (cp) {
973 *fmtStr = cp;
974 *fmtLen = len;
975 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700976 return result;
977
978no_room:
979 result = 1;
980 goto bail;
981}
982
983/**
984 * Convert a binary log entry to ASCII form.
985 *
986 * For convenience we mimic the processLogBuffer API. There is no
987 * pre-defined output length for the binary data, since we're free to format
988 * it however we choose, which means we can't really use a fixed-size buffer
989 * here.
990 */
Mark Salyzynbe1d3c22016-03-10 08:25:33 -0800991LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer(
992 struct logger_entry *buf,
993 AndroidLogEntry *entry,
Mark Salyzyn8dcd94b2016-11-07 13:54:42 -0800994 const EventTagMap *map __unused, // only on !__ANDROID__
Mark Salyzynbe1d3c22016-03-10 08:25:33 -0800995 char *messageBuf, int messageBufLen)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700996{
997 size_t inCount;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700998 uint32_t tagIndex;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700999 const unsigned char* eventData;
1000
1001 entry->tv_sec = buf->sec;
1002 entry->tv_nsec = buf->nsec;
1003 entry->priority = ANDROID_LOG_INFO;
Mark Salyzyn90e7af32015-12-07 16:52:42 -08001004 entry->uid = -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001005 entry->pid = buf->pid;
1006 entry->tid = buf->tid;
1007
1008 /*
Mark Salyzyn7bc80232015-12-11 12:32:53 -08001009 * Pull the tag out, fill in some additional details based on incoming
1010 * buffer version (v3 adds lid, v4 adds uid).
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001011 */
1012 eventData = (const unsigned char*) buf->msg;
Mark Salyzyn40b21552013-12-18 12:59:01 -08001013 struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
1014 if (buf2->hdr_size) {
Mark Salyzyn305374c2016-08-18 14:59:41 -07001015 if ((buf2->hdr_size < sizeof(((struct log_msg *)NULL)->entry_v1)) ||
1016 (buf2->hdr_size > sizeof(((struct log_msg *)NULL)->entry))) {
1017 fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
1018 return -1;
1019 }
Mark Salyzyn40b21552013-12-18 12:59:01 -08001020 eventData = ((unsigned char *)buf2) + buf2->hdr_size;
Mark Salyzyn7bc80232015-12-11 12:32:53 -08001021 if ((buf2->hdr_size >= sizeof(struct logger_entry_v3)) &&
1022 (((struct logger_entry_v3 *)buf)->lid == LOG_ID_SECURITY)) {
1023 entry->priority = ANDROID_LOG_WARN;
1024 }
Mark Salyzyn90e7af32015-12-07 16:52:42 -08001025 if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
1026 entry->uid = ((struct logger_entry_v4 *)buf)->uid;
1027 }
Mark Salyzyn40b21552013-12-18 12:59:01 -08001028 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001029 inCount = buf->len;
Mark Salyzyn1a57ae32016-11-11 14:41:30 -08001030 if (inCount < 4) return -1;
Mark Salyzyn8470dad2015-03-06 20:42:57 +00001031 tagIndex = get4LE(eventData);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001032 eventData += 4;
1033 inCount -= 4;
1034
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001035 entry->tagLen = 0;
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001036 entry->tag = NULL;
1037#ifdef __ANDROID__
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001038 if (map != NULL) {
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001039 entry->tag = android_lookupEventTag_len(map, &entry->tagLen, tagIndex);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001040 }
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001041#endif
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001042
1043 /*
1044 * If we don't have a map, or didn't find the tag number in the map,
1045 * stuff a generated tag value into the start of the output buffer and
1046 * shift the buffer pointers down.
1047 */
1048 if (entry->tag == NULL) {
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001049 size_t tagLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001050
Mark Salyzyn4fd05072016-10-18 11:30:11 -07001051 tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001052 if (tagLen >= (size_t)messageBufLen) {
1053 tagLen = messageBufLen - 1;
1054 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001055 entry->tag = messageBuf;
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001056 entry->tagLen = tagLen;
1057 messageBuf += tagLen + 1;
1058 messageBufLen -= tagLen + 1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001059 }
1060
1061 /*
1062 * Format the event log data into the buffer.
1063 */
Mark Salyzyn4fd05072016-10-18 11:30:11 -07001064 const char* fmtStr = NULL;
1065 size_t fmtLen = 0;
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001066#ifdef __ANDROID__
Mark Salyzyn4fd05072016-10-18 11:30:11 -07001067 if (descriptive_output && map) {
1068 fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
1069 }
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001070#endif
Mark Salyzyn1a57ae32016-11-11 14:41:30 -08001071
1072 char* outBuf = messageBuf;
1073 size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
1074 int result = 0;
1075
1076 if ((inCount > 0) || fmtLen) {
1077 result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
1078 &outRemaining, &fmtStr, &fmtLen);
1079 }
Mark Salyzyn4fd05072016-10-18 11:30:11 -07001080 if ((result == 1) && fmtStr) {
1081 /* We overflowed :-(, let's repaint the line w/o format dressings */
1082 eventData = (const unsigned char*)buf->msg;
1083 if (buf2->hdr_size) {
1084 eventData = ((unsigned char *)buf2) + buf2->hdr_size;
1085 }
1086 eventData += 4;
1087 outBuf = messageBuf;
1088 outRemaining = messageBufLen - 1;
1089 result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
1090 &outRemaining, NULL, NULL);
1091 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001092 if (result < 0) {
1093 fprintf(stderr, "Binary log entry conversion failed\n");
Mark Salyzyn1a57ae32016-11-11 14:41:30 -08001094 }
1095 if (result) {
1096 if (!outRemaining) {
1097 /* make space to leave an indicator */
1098 --outBuf;
1099 ++outRemaining;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001100 }
Mark Salyzyn1a57ae32016-11-11 14:41:30 -08001101 *outBuf++ = (result < 0) ? '!' : '^'; /* Error or Truncation? */
1102 outRemaining--;
1103 /* pretend we ate all the data to prevent log stutter */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001104 inCount = 0;
Mark Salyzyn538bc122016-11-16 15:28:31 -08001105 if (result > 0) result = 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001106 }
1107
1108 /* eat the silly terminating '\n' */
1109 if (inCount == 1 && *eventData == '\n') {
1110 eventData++;
1111 inCount--;
1112 }
1113
1114 if (inCount != 0) {
1115 fprintf(stderr,
Andrew Hsiehd2c8f522012-02-27 16:48:18 -08001116 "Warning: leftover binary log data (%zu bytes)\n", inCount);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001117 }
1118
1119 /*
1120 * Terminate the buffer. The NUL byte does not count as part of
1121 * entry->messageLen.
1122 */
1123 *outBuf = '\0';
1124 entry->messageLen = outBuf - messageBuf;
1125 assert(entry->messageLen == (messageBufLen-1) - outRemaining);
1126
1127 entry->message = messageBuf;
1128
Mark Salyzyn538bc122016-11-16 15:28:31 -08001129 return result;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001130}
1131
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001132/*
1133 * One utf8 character at a time
1134 *
1135 * Returns the length of the utf8 character in the buffer,
1136 * or -1 if illegal or truncated
1137 *
1138 * Open coded from libutils/Unicode.cpp, borrowed from utf8_length(),
1139 * can not remove from here because of library circular dependencies.
1140 * Expect one-day utf8_character_length with the same signature could
1141 * _also_ be part of libutils/Unicode.cpp if its usefullness needs to
1142 * propagate globally.
1143 */
Mark Salyzynbe1d3c22016-03-10 08:25:33 -08001144LIBLOG_WEAK ssize_t utf8_character_length(const char *src, size_t len)
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001145{
1146 const char *cur = src;
1147 const char first_char = *cur++;
1148 static const uint32_t kUnicodeMaxCodepoint = 0x0010FFFF;
1149 int32_t mask, to_ignore_mask;
1150 size_t num_to_read;
1151 uint32_t utf32;
1152
1153 if ((first_char & 0x80) == 0) { /* ASCII */
Mark Salyzynfaa92e92015-09-08 07:57:27 -07001154 return first_char ? 1 : -1;
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001155 }
1156
1157 /*
1158 * (UTF-8's character must not be like 10xxxxxx,
1159 * but 110xxxxx, 1110xxxx, ... or 1111110x)
1160 */
1161 if ((first_char & 0x40) == 0) {
1162 return -1;
1163 }
1164
1165 for (utf32 = 1, num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
1166 num_to_read < 5 && (first_char & mask);
1167 num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
1168 if (num_to_read > len) {
1169 return -1;
1170 }
1171 if ((*cur & 0xC0) != 0x80) { /* can not be 10xxxxxx? */
1172 return -1;
1173 }
1174 utf32 = (utf32 << 6) + (*cur++ & 0b00111111);
1175 }
1176 /* "first_char" must be (110xxxxx - 11110xxx) */
1177 if (num_to_read >= 5) {
1178 return -1;
1179 }
1180 to_ignore_mask |= mask;
1181 utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
1182 if (utf32 > kUnicodeMaxCodepoint) {
1183 return -1;
1184 }
1185 return num_to_read;
1186}
1187
1188/*
1189 * Convert to printable from message to p buffer, return string length. If p is
1190 * NULL, do not copy, but still return the expected string length.
1191 */
1192static size_t convertPrintable(char *p, const char *message, size_t messageLen)
1193{
1194 char *begin = p;
1195 bool print = p != NULL;
1196
1197 while (messageLen) {
1198 char buf[6];
1199 ssize_t len = sizeof(buf) - 1;
1200 if ((size_t)len > messageLen) {
1201 len = messageLen;
1202 }
1203 len = utf8_character_length(message, len);
1204
1205 if (len < 0) {
1206 snprintf(buf, sizeof(buf),
1207 ((messageLen > 1) && isdigit(message[1]))
1208 ? "\\%03o"
1209 : "\\%o",
1210 *message & 0377);
1211 len = 1;
1212 } else {
1213 buf[0] = '\0';
1214 if (len == 1) {
1215 if (*message == '\a') {
1216 strcpy(buf, "\\a");
1217 } else if (*message == '\b') {
1218 strcpy(buf, "\\b");
1219 } else if (*message == '\t') {
Mark Salyzyn65d5ca22015-11-18 09:58:00 -08001220 strcpy(buf, "\t"); // Do not escape tabs
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001221 } else if (*message == '\v') {
1222 strcpy(buf, "\\v");
1223 } else if (*message == '\f') {
1224 strcpy(buf, "\\f");
1225 } else if (*message == '\r') {
1226 strcpy(buf, "\\r");
1227 } else if (*message == '\\') {
1228 strcpy(buf, "\\\\");
1229 } else if ((*message < ' ') || (*message & 0x80)) {
1230 snprintf(buf, sizeof(buf), "\\%o", *message & 0377);
1231 }
1232 }
1233 if (!buf[0]) {
1234 strncpy(buf, message, len);
1235 buf[len] = '\0';
1236 }
1237 }
1238 if (print) {
1239 strcpy(p, buf);
1240 }
1241 p += strlen(buf);
1242 message += len;
1243 messageLen -= len;
1244 }
1245 return p - begin;
1246}
1247
Mark Salyzynbe1d3c22016-03-10 08:25:33 -08001248static char *readSeconds(char *e, struct timespec *t)
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001249{
1250 unsigned long multiplier;
1251 char *p;
1252 t->tv_sec = strtoul(e, &p, 10);
1253 if (*p != '.') {
1254 return NULL;
1255 }
1256 t->tv_nsec = 0;
1257 multiplier = NS_PER_SEC;
1258 while (isdigit(*++p) && (multiplier /= 10)) {
1259 t->tv_nsec += (*p - '0') * multiplier;
1260 }
1261 return p;
1262}
1263
1264static struct timespec *sumTimespec(struct timespec *left,
1265 struct timespec *right)
1266{
1267 left->tv_nsec += right->tv_nsec;
1268 left->tv_sec += right->tv_sec;
1269 if (left->tv_nsec >= (long)NS_PER_SEC) {
1270 left->tv_nsec -= NS_PER_SEC;
1271 left->tv_sec += 1;
1272 }
1273 return left;
1274}
1275
1276static struct timespec *subTimespec(struct timespec *result,
1277 struct timespec *left,
1278 struct timespec *right)
1279{
1280 result->tv_nsec = left->tv_nsec - right->tv_nsec;
1281 result->tv_sec = left->tv_sec - right->tv_sec;
1282 if (result->tv_nsec < 0) {
1283 result->tv_nsec += NS_PER_SEC;
1284 result->tv_sec -= 1;
1285 }
1286 return result;
1287}
1288
1289static long long nsecTimespec(struct timespec *now)
1290{
1291 return (long long)now->tv_sec * NS_PER_SEC + now->tv_nsec;
1292}
1293
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001294#ifdef __ANDROID__
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001295static void convertMonotonic(struct timespec *result,
1296 const AndroidLogEntry *entry)
1297{
1298 struct listnode *node;
1299 struct conversionList {
1300 struct listnode node; /* first */
1301 struct timespec time;
1302 struct timespec convert;
1303 } *list, *next;
1304 struct timespec time, convert;
1305
1306 /* If we do not have a conversion list, build one up */
1307 if (list_empty(&convertHead)) {
1308 bool suspended_pending = false;
1309 struct timespec suspended_monotonic = { 0, 0 };
1310 struct timespec suspended_diff = { 0, 0 };
1311
1312 /*
1313 * Read dmesg for _some_ synchronization markers and insert
1314 * Anything in the Android Logger before the dmesg logging span will
1315 * be highly suspect regarding the monotonic time calculations.
1316 */
Mark Salyzyn78786da2016-04-28 16:06:24 -07001317 FILE *p = popen("/system/bin/dmesg", "re");
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001318 if (p) {
1319 char *line = NULL;
1320 size_t len = 0;
1321 while (getline(&line, &len, p) > 0) {
1322 static const char suspend[] = "PM: suspend entry ";
1323 static const char resume[] = "PM: suspend exit ";
1324 static const char healthd[] = "healthd";
1325 static const char battery[] = ": battery ";
1326 static const char suspended[] = "Suspended for ";
1327 struct timespec monotonic;
1328 struct tm tm;
1329 char *cp, *e = line;
1330 bool add_entry = true;
1331
1332 if (*e == '<') {
1333 while (*e && (*e != '>')) {
1334 ++e;
1335 }
1336 if (*e != '>') {
1337 continue;
1338 }
1339 }
1340 if (*e != '[') {
1341 continue;
1342 }
1343 while (*++e == ' ') {
1344 ;
1345 }
1346 e = readSeconds(e, &monotonic);
1347 if (!e || (*e != ']')) {
1348 continue;
1349 }
1350
1351 if ((e = strstr(e, suspend))) {
1352 e += sizeof(suspend) - 1;
1353 } else if ((e = strstr(line, resume))) {
1354 e += sizeof(resume) - 1;
1355 } else if (((e = strstr(line, healthd)))
1356 && ((e = strstr(e + sizeof(healthd) - 1, battery)))) {
1357 /* NB: healthd is roughly 150us late, worth the price to
1358 * deal with ntp-induced or hardware clock drift. */
1359 e += sizeof(battery) - 1;
1360 } else if ((e = strstr(line, suspended))) {
1361 e += sizeof(suspended) - 1;
1362 e = readSeconds(e, &time);
1363 if (!e) {
1364 continue;
1365 }
1366 add_entry = false;
1367 suspended_pending = true;
1368 suspended_monotonic = monotonic;
1369 suspended_diff = time;
1370 } else {
1371 continue;
1372 }
1373 if (add_entry) {
1374 /* look for "????-??-?? ??:??:??.????????? UTC" */
1375 cp = strstr(e, " UTC");
1376 if (!cp || ((cp - e) < 29) || (cp[-10] != '.')) {
1377 continue;
1378 }
1379 e = cp - 29;
1380 cp = readSeconds(cp - 10, &time);
1381 if (!cp) {
1382 continue;
1383 }
1384 cp = strptime(e, "%Y-%m-%d %H:%M:%S.", &tm);
1385 if (!cp) {
1386 continue;
1387 }
1388 cp = getenv(tz);
1389 if (cp) {
1390 cp = strdup(cp);
1391 }
1392 setenv(tz, utc, 1);
1393 time.tv_sec = mktime(&tm);
1394 if (cp) {
1395 setenv(tz, cp, 1);
1396 free(cp);
1397 } else {
1398 unsetenv(tz);
1399 }
1400 list = calloc(1, sizeof(struct conversionList));
1401 list_init(&list->node);
1402 list->time = time;
1403 subTimespec(&list->convert, &time, &monotonic);
1404 list_add_tail(&convertHead, &list->node);
1405 }
1406 if (suspended_pending && !list_empty(&convertHead)) {
1407 list = node_to_item(list_tail(&convertHead),
1408 struct conversionList, node);
1409 if (subTimespec(&time,
1410 subTimespec(&time,
1411 &list->time,
1412 &list->convert),
1413 &suspended_monotonic)->tv_sec > 0) {
1414 /* resume, what is convert factor before? */
1415 subTimespec(&convert, &list->convert, &suspended_diff);
1416 } else {
1417 /* suspend */
1418 convert = list->convert;
1419 }
1420 time = suspended_monotonic;
1421 sumTimespec(&time, &convert);
1422 /* breakpoint just before sleep */
1423 list = calloc(1, sizeof(struct conversionList));
1424 list_init(&list->node);
1425 list->time = time;
1426 list->convert = convert;
1427 list_add_tail(&convertHead, &list->node);
1428 /* breakpoint just after sleep */
1429 list = calloc(1, sizeof(struct conversionList));
1430 list_init(&list->node);
1431 list->time = time;
1432 sumTimespec(&list->time, &suspended_diff);
1433 list->convert = convert;
1434 sumTimespec(&list->convert, &suspended_diff);
1435 list_add_tail(&convertHead, &list->node);
1436 suspended_pending = false;
1437 }
1438 }
1439 pclose(p);
1440 }
1441 /* last entry is our current time conversion */
1442 list = calloc(1, sizeof(struct conversionList));
1443 list_init(&list->node);
1444 clock_gettime(CLOCK_REALTIME, &list->time);
1445 clock_gettime(CLOCK_MONOTONIC, &convert);
1446 clock_gettime(CLOCK_MONOTONIC, &time);
1447 /* Correct for instant clock_gettime latency (syscall or ~30ns) */
1448 subTimespec(&time, &convert, subTimespec(&time, &time, &convert));
1449 /* Calculate conversion factor */
1450 subTimespec(&list->convert, &list->time, &time);
1451 list_add_tail(&convertHead, &list->node);
1452 if (suspended_pending) {
1453 /* manufacture a suspend @ point before */
1454 subTimespec(&convert, &list->convert, &suspended_diff);
1455 time = suspended_monotonic;
1456 sumTimespec(&time, &convert);
1457 /* breakpoint just after sleep */
1458 list = calloc(1, sizeof(struct conversionList));
1459 list_init(&list->node);
1460 list->time = time;
1461 sumTimespec(&list->time, &suspended_diff);
1462 list->convert = convert;
1463 sumTimespec(&list->convert, &suspended_diff);
1464 list_add_head(&convertHead, &list->node);
1465 /* breakpoint just before sleep */
1466 list = calloc(1, sizeof(struct conversionList));
1467 list_init(&list->node);
1468 list->time = time;
1469 list->convert = convert;
1470 list_add_head(&convertHead, &list->node);
1471 }
1472 }
1473
1474 /* Find the breakpoint in the conversion list */
1475 list = node_to_item(list_head(&convertHead), struct conversionList, node);
1476 next = NULL;
1477 list_for_each(node, &convertHead) {
1478 next = node_to_item(node, struct conversionList, node);
1479 if (entry->tv_sec < next->time.tv_sec) {
1480 break;
1481 } else if (entry->tv_sec == next->time.tv_sec) {
1482 if (entry->tv_nsec < next->time.tv_nsec) {
1483 break;
1484 }
1485 }
1486 list = next;
1487 }
1488
1489 /* blend time from one breakpoint to the next */
1490 convert = list->convert;
1491 if (next) {
1492 unsigned long long total, run;
1493
1494 total = nsecTimespec(subTimespec(&time, &next->time, &list->time));
1495 time.tv_sec = entry->tv_sec;
1496 time.tv_nsec = entry->tv_nsec;
1497 run = nsecTimespec(subTimespec(&time, &time, &list->time));
1498 if (run < total) {
1499 long long crun;
1500
1501 float f = nsecTimespec(subTimespec(&time, &next->convert, &convert));
1502 f *= run;
1503 f /= total;
1504 crun = f;
1505 convert.tv_sec += crun / (long long)NS_PER_SEC;
1506 if (crun < 0) {
1507 convert.tv_nsec -= (-crun) % NS_PER_SEC;
1508 if (convert.tv_nsec < 0) {
1509 convert.tv_nsec += NS_PER_SEC;
1510 convert.tv_sec -= 1;
1511 }
1512 } else {
1513 convert.tv_nsec += crun % NS_PER_SEC;
1514 if (convert.tv_nsec >= (long)NS_PER_SEC) {
1515 convert.tv_nsec -= NS_PER_SEC;
1516 convert.tv_sec += 1;
1517 }
1518 }
1519 }
1520 }
1521
1522 /* Apply the correction factor */
1523 result->tv_sec = entry->tv_sec;
1524 result->tv_nsec = entry->tv_nsec;
1525 subTimespec(result, result, &convert);
1526}
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001527#endif
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001528
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001529/**
1530 * Formats a log message into a buffer
1531 *
1532 * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
1533 * If return value != defaultBuffer, caller must call free()
1534 * Returns NULL on malloc error
1535 */
1536
Mark Salyzynbe1d3c22016-03-10 08:25:33 -08001537LIBLOG_ABI_PUBLIC char *android_log_formatLogLine (
1538 AndroidLogFormat *p_format,
1539 char *defaultBuffer,
1540 size_t defaultBufferSize,
1541 const AndroidLogEntry *entry,
1542 size_t *p_outLength)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001543{
Yabin Cui8a985352014-11-13 10:02:08 -08001544#if !defined(_WIN32)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001545 struct tm tmBuf;
1546#endif
1547 struct tm* ptm;
Mark Salyzyn9b4d7e12017-01-30 09:16:09 -08001548 /* good margin, 23+nul for msec, 26+nul for usec, 29+nul to nsec */
1549 char timeBuf[64];
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001550 char prefixBuf[128], suffixBuf[128];
1551 char priChar;
1552 int prefixSuffixIsHeaderFooter = 0;
Mark Salyzyn90e7af32015-12-07 16:52:42 -08001553 char *ret;
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001554 time_t now;
1555 unsigned long nsec;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001556
1557 priChar = filterPriToChar(entry->priority);
Pierre Zurekead88fc2010-10-17 22:39:37 +02001558 size_t prefixLen = 0, suffixLen = 0;
1559 size_t len;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001560
1561 /*
1562 * Get the current date/time in pretty form
1563 *
1564 * It's often useful when examining a log with "less" to jump to
1565 * a specific point in the file by searching for the date/time stamp.
1566 * For this reason it's very annoying to have regexp meta characters
1567 * in the time stamp. Don't use forward slashes, parenthesis,
1568 * brackets, asterisks, or other special chars here.
Mark Salyzynf28f6a92015-08-31 08:01:33 -07001569 *
1570 * The caller may have affected the timezone environment, this is
1571 * expected to be sensitive to that.
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001572 */
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001573 now = entry->tv_sec;
1574 nsec = entry->tv_nsec;
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001575#if __ANDROID__
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001576 if (p_format->monotonic_output) {
Mark Salyzynb6bee332015-09-08 08:56:32 -07001577 // prevent convertMonotonic from being called if logd is monotonic
Mark Salyzynba7a9a02015-12-01 15:57:25 -08001578 if (android_log_clockid() != CLOCK_MONOTONIC) {
Mark Salyzynb6bee332015-09-08 08:56:32 -07001579 struct timespec time;
1580 convertMonotonic(&time, entry);
1581 now = time.tv_sec;
1582 nsec = time.tv_nsec;
1583 }
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001584 }
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001585#endif
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001586 if (now < 0) {
1587 nsec = NS_PER_SEC - nsec;
1588 }
1589 if (p_format->epoch_output || p_format->monotonic_output) {
1590 ptm = NULL;
1591 snprintf(timeBuf, sizeof(timeBuf),
1592 p_format->monotonic_output ? "%6lld" : "%19lld",
1593 (long long)now);
1594 } else {
Yabin Cui8a985352014-11-13 10:02:08 -08001595#if !defined(_WIN32)
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001596 ptm = localtime_r(&now, &tmBuf);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001597#else
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001598 ptm = localtime(&now);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001599#endif
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001600 strftime(timeBuf, sizeof(timeBuf),
1601 &"%Y-%m-%d %H:%M:%S"[p_format->year_output ? 0 : 3],
1602 ptm);
1603 }
Mark Salyzyne1f20042015-05-06 08:40:40 -07001604 len = strlen(timeBuf);
Mark Salyzyn9b4d7e12017-01-30 09:16:09 -08001605 if (p_format->nsec_time_output) {
1606 len += snprintf(timeBuf + len, sizeof(timeBuf) - len,
1607 ".%09ld", nsec);
1608 } else if (p_format->usec_time_output) {
Mark Salyzynf28f6a92015-08-31 08:01:33 -07001609 len += snprintf(timeBuf + len, sizeof(timeBuf) - len,
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001610 ".%06ld", nsec / US_PER_NSEC);
Mark Salyzyne1f20042015-05-06 08:40:40 -07001611 } else {
Mark Salyzynf28f6a92015-08-31 08:01:33 -07001612 len += snprintf(timeBuf + len, sizeof(timeBuf) - len,
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001613 ".%03ld", nsec / MS_PER_NSEC);
Mark Salyzynf28f6a92015-08-31 08:01:33 -07001614 }
Mark Salyzyn4cbed022015-08-31 15:53:41 -07001615 if (p_format->zone_output && ptm) {
Mark Salyzynf28f6a92015-08-31 08:01:33 -07001616 strftime(timeBuf + len, sizeof(timeBuf) - len, " %z", ptm);
Mark Salyzyne1f20042015-05-06 08:40:40 -07001617 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001618
1619 /*
1620 * Construct a buffer containing the log header and log message.
1621 */
Pierre Zurekead88fc2010-10-17 22:39:37 +02001622 if (p_format->colored_output) {
1623 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[38;5;%dm",
1624 colorFromPri(entry->priority));
1625 prefixLen = MIN(prefixLen, sizeof(prefixBuf));
1626 suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), "\x1B[0m");
1627 suffixLen = MIN(suffixLen, sizeof(suffixBuf));
1628 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001629
Mark Salyzyn90e7af32015-12-07 16:52:42 -08001630 char uid[16];
1631 uid[0] = '\0';
1632 if (p_format->uid_output) {
1633 if (entry->uid >= 0) {
Mark Salyzyn2aa510e2015-12-08 09:15:06 -08001634
William Roberts8a5b9ca2016-04-08 12:13:17 -07001635 /*
1636 * This code is Android specific, bionic guarantees that
1637 * calls to non-reentrant getpwuid() are thread safe.
1638 */
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001639#if !defined(__MINGW32__)
1640#if (FAKE_LOG_DEVICE == 0)
William Roberts8a5b9ca2016-04-08 12:13:17 -07001641#ifndef __BIONIC__
1642#warning "This code assumes that getpwuid is thread safe, only true with Bionic!"
1643#endif
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001644#endif
William Roberts8a5b9ca2016-04-08 12:13:17 -07001645 struct passwd* pwd = getpwuid(entry->uid);
1646 if (pwd && (strlen(pwd->pw_name) <= 5)) {
1647 snprintf(uid, sizeof(uid), "%5s:", pwd->pw_name);
Mark Salyzyn62d0d2d2016-03-08 16:18:26 -08001648 } else
1649#endif
1650 {
Mark Salyzyn2aa510e2015-12-08 09:15:06 -08001651 // Not worth parsing package list, names all longer than 5
1652 snprintf(uid, sizeof(uid), "%5d:", entry->uid);
1653 }
Mark Salyzyn90e7af32015-12-07 16:52:42 -08001654 } else {
1655 snprintf(uid, sizeof(uid), " ");
1656 }
1657 }
1658
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001659 switch (p_format->format) {
1660 case FORMAT_TAG:
Pierre Zurekead88fc2010-10-17 22:39:37 +02001661 len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001662 "%c/%-8.*s: ", priChar, (int)entry->tagLen, entry->tag);
Pierre Zurekead88fc2010-10-17 22:39:37 +02001663 strcpy(suffixBuf + suffixLen, "\n");
1664 ++suffixLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001665 break;
1666 case FORMAT_PROCESS:
Pierre Zurekead88fc2010-10-17 22:39:37 +02001667 len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen,
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001668 " (%.*s)\n", (int)entry->tagLen, entry->tag);
Pierre Zurekead88fc2010-10-17 22:39:37 +02001669 suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
1670 len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
Mark Salyzyn90e7af32015-12-07 16:52:42 -08001671 "%c(%s%5d) ", priChar, uid, entry->pid);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001672 break;
1673 case FORMAT_THREAD:
Pierre Zurekead88fc2010-10-17 22:39:37 +02001674 len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
Mark Salyzyn90e7af32015-12-07 16:52:42 -08001675 "%c(%s%5d:%5d) ", priChar, uid, entry->pid, entry->tid);
Pierre Zurekead88fc2010-10-17 22:39:37 +02001676 strcpy(suffixBuf + suffixLen, "\n");
1677 ++suffixLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001678 break;
1679 case FORMAT_RAW:
Pierre Zurekead88fc2010-10-17 22:39:37 +02001680 prefixBuf[prefixLen] = 0;
1681 len = 0;
1682 strcpy(suffixBuf + suffixLen, "\n");
1683 ++suffixLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001684 break;
1685 case FORMAT_TIME:
Pierre Zurekead88fc2010-10-17 22:39:37 +02001686 len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001687 "%s %c/%-8.*s(%s%5d): ", timeBuf, priChar,
1688 (int)entry->tagLen, entry->tag, uid, entry->pid);
Pierre Zurekead88fc2010-10-17 22:39:37 +02001689 strcpy(suffixBuf + suffixLen, "\n");
1690 ++suffixLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001691 break;
1692 case FORMAT_THREADTIME:
Mark Salyzyn90e7af32015-12-07 16:52:42 -08001693 ret = strchr(uid, ':');
1694 if (ret) {
1695 *ret = ' ';
1696 }
Pierre Zurekead88fc2010-10-17 22:39:37 +02001697 len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001698 "%s %s%5d %5d %c %-8.*s: ", timeBuf, uid, entry->pid,
1699 entry->tid, priChar, (int)entry->tagLen, entry->tag);
Pierre Zurekead88fc2010-10-17 22:39:37 +02001700 strcpy(suffixBuf + suffixLen, "\n");
1701 ++suffixLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001702 break;
1703 case FORMAT_LONG:
Pierre Zurekead88fc2010-10-17 22:39:37 +02001704 len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001705 "[ %s %s%5d:%5d %c/%-8.*s ]\n",
1706 timeBuf, uid, entry->pid, entry->tid, priChar,
1707 (int)entry->tagLen, entry->tag);
Pierre Zurekead88fc2010-10-17 22:39:37 +02001708 strcpy(suffixBuf + suffixLen, "\n\n");
1709 suffixLen += 2;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001710 prefixSuffixIsHeaderFooter = 1;
1711 break;
1712 case FORMAT_BRIEF:
1713 default:
Pierre Zurekead88fc2010-10-17 22:39:37 +02001714 len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
Mark Salyzyn807e40e2016-09-22 09:56:51 -07001715 "%c/%-8.*s(%s%5d): ", priChar, (int)entry->tagLen, entry->tag,
1716 uid, entry->pid);
Pierre Zurekead88fc2010-10-17 22:39:37 +02001717 strcpy(suffixBuf + suffixLen, "\n");
1718 ++suffixLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001719 break;
1720 }
Pierre Zurekead88fc2010-10-17 22:39:37 +02001721
Keith Prestonb45b5c92010-02-11 15:12:53 -06001722 /* snprintf has a weird return value. It returns what would have been
1723 * written given a large enough buffer. In the case that the prefix is
1724 * longer then our buffer(128), it messes up the calculations below
1725 * possibly causing heap corruption. To avoid this we double check and
1726 * set the length at the maximum (size minus null byte)
1727 */
Mark Salyzyn2f83d672016-03-11 12:06:12 -08001728 prefixLen += len;
1729 if (prefixLen >= sizeof(prefixBuf)) {
1730 prefixLen = sizeof(prefixBuf) - 1;
1731 prefixBuf[sizeof(prefixBuf) - 1] = '\0';
1732 }
1733 if (suffixLen >= sizeof(suffixBuf)) {
1734 suffixLen = sizeof(suffixBuf) - 1;
1735 suffixBuf[sizeof(suffixBuf) - 2] = '\n';
1736 suffixBuf[sizeof(suffixBuf) - 1] = '\0';
1737 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001738
1739 /* the following code is tragically unreadable */
1740
1741 size_t numLines;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001742 char *p;
1743 size_t bufferSize;
1744 const char *pm;
1745
1746 if (prefixSuffixIsHeaderFooter) {
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001747 /* we're just wrapping message with a header/footer */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001748 numLines = 1;
1749 } else {
1750 pm = entry->message;
1751 numLines = 0;
1752
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001753 /*
1754 * The line-end finding here must match the line-end finding
1755 * in for ( ... numLines...) loop below
1756 */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001757 while (pm < (entry->message + entry->messageLen)) {
1758 if (*pm++ == '\n') numLines++;
1759 }
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001760 /* plus one line for anything not newline-terminated at the end */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001761 if (pm > entry->message && *(pm-1) != '\n') numLines++;
1762 }
1763
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001764 /*
1765 * this is an upper bound--newlines in message may be counted
1766 * extraneously
1767 */
1768 bufferSize = (numLines * (prefixLen + suffixLen)) + 1;
1769 if (p_format->printable_output) {
1770 /* Calculate extra length to convert non-printable to printable */
1771 bufferSize += convertPrintable(NULL, entry->message, entry->messageLen);
1772 } else {
1773 bufferSize += entry->messageLen;
1774 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001775
1776 if (defaultBufferSize >= bufferSize) {
1777 ret = defaultBuffer;
1778 } else {
1779 ret = (char *)malloc(bufferSize);
1780
1781 if (ret == NULL) {
1782 return ret;
1783 }
1784 }
1785
1786 ret[0] = '\0'; /* to start strcat off */
1787
1788 p = ret;
1789 pm = entry->message;
1790
1791 if (prefixSuffixIsHeaderFooter) {
1792 strcat(p, prefixBuf);
1793 p += prefixLen;
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001794 if (p_format->printable_output) {
1795 p += convertPrintable(p, entry->message, entry->messageLen);
1796 } else {
1797 strncat(p, entry->message, entry->messageLen);
1798 p += entry->messageLen;
1799 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001800 strcat(p, suffixBuf);
1801 p += suffixLen;
1802 } else {
Mark Salyzyn7cc80132016-01-20 13:52:46 -08001803 do {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001804 const char *lineStart;
1805 size_t lineLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001806 lineStart = pm;
1807
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001808 /* Find the next end-of-line in message */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001809 while (pm < (entry->message + entry->messageLen)
1810 && *pm != '\n') pm++;
1811 lineLen = pm - lineStart;
1812
1813 strcat(p, prefixBuf);
1814 p += prefixLen;
Mark Salyzynb932b2f2015-05-15 09:01:58 -07001815 if (p_format->printable_output) {
1816 p += convertPrintable(p, lineStart, lineLen);
1817 } else {
1818 strncat(p, lineStart, lineLen);
1819 p += lineLen;
1820 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001821 strcat(p, suffixBuf);
1822 p += suffixLen;
1823
1824 if (*pm == '\n') pm++;
Mark Salyzyn7cc80132016-01-20 13:52:46 -08001825 } while (pm < (entry->message + entry->messageLen));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001826 }
1827
1828 if (p_outLength != NULL) {
1829 *p_outLength = p - ret;
1830 }
1831
1832 return ret;
1833}
1834
1835/**
1836 * Either print or do not print log line, based on filter
1837 *
1838 * Returns count bytes written
1839 */
1840
Mark Salyzynbe1d3c22016-03-10 08:25:33 -08001841LIBLOG_ABI_PUBLIC int android_log_printLogLine(
1842 AndroidLogFormat *p_format,
1843 int fd,
1844 const AndroidLogEntry *entry)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001845{
1846 int ret;
1847 char defaultBuffer[512];
1848 char *outBuffer = NULL;
1849 size_t totalLen;
1850
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001851 outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
1852 sizeof(defaultBuffer), entry, &totalLen);
1853
Mark Salyzyn1a57ae32016-11-11 14:41:30 -08001854 if (!outBuffer) return -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001855
1856 do {
1857 ret = write(fd, outBuffer, totalLen);
1858 } while (ret < 0 && errno == EINTR);
1859
1860 if (ret < 0) {
1861 fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
1862 ret = 0;
1863 goto done;
1864 }
1865
1866 if (((size_t)ret) < totalLen) {
1867 fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
1868 (int)totalLen);
1869 goto done;
1870 }
1871
1872done:
1873 if (outBuffer != defaultBuffer) {
1874 free(outBuffer);
1875 }
1876
1877 return ret;
1878}