• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* //device/libs/cutils/logprint.c
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
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 */
19 
20 #include <ctype.h>
21 #include <stdio.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <arpa/inet.h>
28 
29 #include <cutils/logd.h>
30 #include <cutils/logprint.h>
31 
32 typedef struct FilterInfo_t {
33     char *mTag;
34     android_LogPriority mPri;
35     struct FilterInfo_t *p_next;
36 } FilterInfo;
37 
38 struct AndroidLogFormat_t {
39     android_LogPriority global_pri;
40     FilterInfo *filters;
41     AndroidLogPrintFormat format;
42 };
43 
filterinfo_new(const char * tag,android_LogPriority pri)44 static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri)
45 {
46     FilterInfo *p_ret;
47 
48     p_ret = (FilterInfo *)calloc(1, sizeof(FilterInfo));
49     p_ret->mTag = strdup(tag);
50     p_ret->mPri = pri;
51 
52     return p_ret;
53 }
54 
filterinfo_free(FilterInfo * p_info)55 static void filterinfo_free(FilterInfo *p_info)
56 {
57     if (p_info == NULL) {
58         return;
59     }
60 
61     free(p_info->mTag);
62     p_info->mTag = NULL;
63 }
64 
65 /*
66  * Note: also accepts 0-9 priorities
67  * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
68  */
filterCharToPri(char c)69 static android_LogPriority filterCharToPri (char c)
70 {
71     android_LogPriority pri;
72 
73     c = tolower(c);
74 
75     if (c >= '0' && c <= '9') {
76         if (c >= ('0'+ANDROID_LOG_SILENT)) {
77             pri = ANDROID_LOG_VERBOSE;
78         } else {
79             pri = (android_LogPriority)(c - '0');
80         }
81     } else if (c == 'v') {
82         pri = ANDROID_LOG_VERBOSE;
83     } else if (c == 'd') {
84         pri = ANDROID_LOG_DEBUG;
85     } else if (c == 'i') {
86         pri = ANDROID_LOG_INFO;
87     } else if (c == 'w') {
88         pri = ANDROID_LOG_WARN;
89     } else if (c == 'e') {
90         pri = ANDROID_LOG_ERROR;
91     } else if (c == 'f') {
92         pri = ANDROID_LOG_FATAL;
93     } else if (c == 's') {
94         pri = ANDROID_LOG_SILENT;
95     } else if (c == '*') {
96         pri = ANDROID_LOG_DEFAULT;
97     } else {
98         pri = ANDROID_LOG_UNKNOWN;
99     }
100 
101     return pri;
102 }
103 
filterPriToChar(android_LogPriority pri)104 static char filterPriToChar (android_LogPriority pri)
105 {
106     switch (pri) {
107         case ANDROID_LOG_VERBOSE:       return 'V';
108         case ANDROID_LOG_DEBUG:         return 'D';
109         case ANDROID_LOG_INFO:          return 'I';
110         case ANDROID_LOG_WARN:          return 'W';
111         case ANDROID_LOG_ERROR:         return 'E';
112         case ANDROID_LOG_FATAL:         return 'F';
113         case ANDROID_LOG_SILENT:        return 'S';
114 
115         case ANDROID_LOG_DEFAULT:
116         case ANDROID_LOG_UNKNOWN:
117         default:                        return '?';
118     }
119 }
120 
filterPriForTag(AndroidLogFormat * p_format,const char * tag)121 static android_LogPriority filterPriForTag(
122         AndroidLogFormat *p_format, const char *tag)
123 {
124     FilterInfo *p_curFilter;
125 
126     for (p_curFilter = p_format->filters
127             ; p_curFilter != NULL
128             ; p_curFilter = p_curFilter->p_next
129     ) {
130         if (0 == strcmp(tag, p_curFilter->mTag)) {
131             if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
132                 return p_format->global_pri;
133             } else {
134                 return p_curFilter->mPri;
135             }
136         }
137     }
138 
139     return p_format->global_pri;
140 }
141 
142 /** for debugging */
dumpFilters(AndroidLogFormat * p_format)143 static void dumpFilters(AndroidLogFormat *p_format)
144 {
145     FilterInfo *p_fi;
146 
147     for (p_fi = p_format->filters ; p_fi != NULL ; p_fi = p_fi->p_next) {
148         char cPri = filterPriToChar(p_fi->mPri);
149         if (p_fi->mPri == ANDROID_LOG_DEFAULT) {
150             cPri = filterPriToChar(p_format->global_pri);
151         }
152         fprintf(stderr,"%s:%c\n", p_fi->mTag, cPri);
153     }
154 
155     fprintf(stderr,"*:%c\n", filterPriToChar(p_format->global_pri));
156 
157 }
158 
159 /**
160  * returns 1 if this log line should be printed based on its priority
161  * and tag, and 0 if it should not
162  */
android_log_shouldPrintLine(AndroidLogFormat * p_format,const char * tag,android_LogPriority pri)163 int android_log_shouldPrintLine (
164         AndroidLogFormat *p_format, const char *tag, android_LogPriority pri)
165 {
166     return pri >= filterPriForTag(p_format, tag);
167 }
168 
android_log_format_new()169 AndroidLogFormat *android_log_format_new()
170 {
171     AndroidLogFormat *p_ret;
172 
173     p_ret = calloc(1, sizeof(AndroidLogFormat));
174 
175     p_ret->global_pri = ANDROID_LOG_VERBOSE;
176     p_ret->format = FORMAT_BRIEF;
177 
178     return p_ret;
179 }
180 
android_log_format_free(AndroidLogFormat * p_format)181 void android_log_format_free(AndroidLogFormat *p_format)
182 {
183     FilterInfo *p_info, *p_info_old;
184 
185     p_info = p_format->filters;
186 
187     while (p_info != NULL) {
188         p_info_old = p_info;
189         p_info = p_info->p_next;
190 
191         free(p_info_old);
192     }
193 
194     free(p_format);
195 }
196 
197 
198 
android_log_setPrintFormat(AndroidLogFormat * p_format,AndroidLogPrintFormat format)199 void android_log_setPrintFormat(AndroidLogFormat *p_format,
200         AndroidLogPrintFormat format)
201 {
202     p_format->format=format;
203 }
204 
205 /**
206  * Returns FORMAT_OFF on invalid string
207  */
android_log_formatFromString(const char * formatString)208 AndroidLogPrintFormat android_log_formatFromString(const char * formatString)
209 {
210     static AndroidLogPrintFormat format;
211 
212     if (strcmp(formatString, "brief") == 0) format = FORMAT_BRIEF;
213     else if (strcmp(formatString, "process") == 0) format = FORMAT_PROCESS;
214     else if (strcmp(formatString, "tag") == 0) format = FORMAT_TAG;
215     else if (strcmp(formatString, "thread") == 0) format = FORMAT_THREAD;
216     else if (strcmp(formatString, "raw") == 0) format = FORMAT_RAW;
217     else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
218     else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
219     else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
220     else format = FORMAT_OFF;
221 
222     return format;
223 }
224 
225 /**
226  * filterExpression: a single filter expression
227  * eg "AT:d"
228  *
229  * returns 0 on success and -1 on invalid expression
230  *
231  * Assumes single threaded execution
232  */
233 
android_log_addFilterRule(AndroidLogFormat * p_format,const char * filterExpression)234 int android_log_addFilterRule(AndroidLogFormat *p_format,
235         const char *filterExpression)
236 {
237     size_t i=0;
238     size_t tagNameLength;
239     android_LogPriority pri = ANDROID_LOG_DEFAULT;
240 
241     tagNameLength = strcspn(filterExpression, ":");
242 
243     if (tagNameLength == 0) {
244         goto error;
245     }
246 
247     if(filterExpression[tagNameLength] == ':') {
248         pri = filterCharToPri(filterExpression[tagNameLength+1]);
249 
250         if (pri == ANDROID_LOG_UNKNOWN) {
251             goto error;
252         }
253     }
254 
255     if(0 == strncmp("*", filterExpression, tagNameLength)) {
256         // This filter expression refers to the global filter
257         // The default level for this is DEBUG if the priority
258         // is unspecified
259         if (pri == ANDROID_LOG_DEFAULT) {
260             pri = ANDROID_LOG_DEBUG;
261         }
262 
263         p_format->global_pri = pri;
264     } else {
265         // for filter expressions that don't refer to the global
266         // filter, the default is verbose if the priority is unspecified
267         if (pri == ANDROID_LOG_DEFAULT) {
268             pri = ANDROID_LOG_VERBOSE;
269         }
270 
271         char *tagName;
272 
273 // Presently HAVE_STRNDUP is never defined, so the second case is always taken
274 // Darwin doesn't have strnup, everything else does
275 #ifdef HAVE_STRNDUP
276         tagName = strndup(filterExpression, tagNameLength);
277 #else
278         //a few extra bytes copied...
279         tagName = strdup(filterExpression);
280         tagName[tagNameLength] = '\0';
281 #endif /*HAVE_STRNDUP*/
282 
283         FilterInfo *p_fi = filterinfo_new(tagName, pri);
284         free(tagName);
285 
286         p_fi->p_next = p_format->filters;
287         p_format->filters = p_fi;
288     }
289 
290     return 0;
291 error:
292     return -1;
293 }
294 
295 
296 /**
297  * filterString: a comma/whitespace-separated set of filter expressions
298  *
299  * eg "AT:d *:i"
300  *
301  * returns 0 on success and -1 on invalid expression
302  *
303  * Assumes single threaded execution
304  *
305  */
306 
android_log_addFilterString(AndroidLogFormat * p_format,const char * filterString)307 int android_log_addFilterString(AndroidLogFormat *p_format,
308         const char *filterString)
309 {
310     char *filterStringCopy = strdup (filterString);
311     char *p_cur = filterStringCopy;
312     char *p_ret;
313     int err;
314 
315     // Yes, I'm using strsep
316     while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
317         // ignore whitespace-only entries
318         if(p_ret[0] != '\0') {
319             err = android_log_addFilterRule(p_format, p_ret);
320 
321             if (err < 0) {
322                 goto error;
323             }
324         }
325     }
326 
327     free (filterStringCopy);
328     return 0;
329 error:
330     free (filterStringCopy);
331     return -1;
332 }
333 
strip_end(char * str)334 static inline char * strip_end(char *str)
335 {
336     char *end = str + strlen(str) - 1;
337 
338     while (end >= str && isspace(*end))
339         *end-- = '\0';
340     return str;
341 }
342 
343 /**
344  * Splits a wire-format buffer into an AndroidLogEntry
345  * entry allocated by caller. Pointers will point directly into buf
346  *
347  * Returns 0 on success and -1 on invalid wire format (entry will be
348  * in unspecified state)
349  */
android_log_processLogBuffer(struct logger_entry * buf,AndroidLogEntry * entry)350 int android_log_processLogBuffer(struct logger_entry *buf,
351                                  AndroidLogEntry *entry)
352 {
353     size_t tag_len;
354 
355     entry->tv_sec = buf->sec;
356     entry->tv_nsec = buf->nsec;
357     entry->priority = buf->msg[0];
358     entry->pid = buf->pid;
359     entry->tid = buf->tid;
360     entry->tag = buf->msg + 1;
361     tag_len = strlen(entry->tag);
362     entry->messageLen = buf->len - tag_len - 3;
363     entry->message = entry->tag + tag_len + 1;
364 
365     return 0;
366 }
367 
368 /*
369  * Extract a 4-byte value from a byte stream.
370  */
get4LE(const uint8_t * src)371 static inline uint32_t get4LE(const uint8_t* src)
372 {
373     return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
374 }
375 
376 /*
377  * Extract an 8-byte value from a byte stream.
378  */
get8LE(const uint8_t * src)379 static inline uint64_t get8LE(const uint8_t* src)
380 {
381     uint32_t low, high;
382 
383     low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
384     high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
385     return ((long long) high << 32) | (long long) low;
386 }
387 
388 
389 /*
390  * Recursively convert binary log data to printable form.
391  *
392  * This needs to be recursive because you can have lists of lists.
393  *
394  * If we run out of room, we stop processing immediately.  It's important
395  * for us to check for space on every output element to avoid producing
396  * garbled output.
397  *
398  * Returns 0 on success, 1 on buffer full, -1 on failure.
399  */
android_log_printBinaryEvent(const unsigned char ** pEventData,size_t * pEventDataLen,char ** pOutBuf,size_t * pOutBufLen)400 static int android_log_printBinaryEvent(const unsigned char** pEventData,
401     size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
402 {
403     const unsigned char* eventData = *pEventData;
404     size_t eventDataLen = *pEventDataLen;
405     char* outBuf = *pOutBuf;
406     size_t outBufLen = *pOutBufLen;
407     unsigned char type;
408     size_t outCount;
409     int result = 0;
410 
411     if (eventDataLen < 1)
412         return -1;
413     type = *eventData++;
414     eventDataLen--;
415 
416     //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
417 
418     switch (type) {
419     case EVENT_TYPE_INT:
420         /* 32-bit signed int */
421         {
422             int ival;
423 
424             if (eventDataLen < 4)
425                 return -1;
426             ival = get4LE(eventData);
427             eventData += 4;
428             eventDataLen -= 4;
429 
430             outCount = snprintf(outBuf, outBufLen, "%d", ival);
431             if (outCount < outBufLen) {
432                 outBuf += outCount;
433                 outBufLen -= outCount;
434             } else {
435                 /* halt output */
436                 goto no_room;
437             }
438         }
439         break;
440     case EVENT_TYPE_LONG:
441         /* 64-bit signed long */
442         {
443             long long lval;
444 
445             if (eventDataLen < 8)
446                 return -1;
447             lval = get8LE(eventData);
448             eventData += 8;
449             eventDataLen -= 8;
450 
451             outCount = snprintf(outBuf, outBufLen, "%lld", lval);
452             if (outCount < outBufLen) {
453                 outBuf += outCount;
454                 outBufLen -= outCount;
455             } else {
456                 /* halt output */
457                 goto no_room;
458             }
459         }
460         break;
461     case EVENT_TYPE_STRING:
462         /* UTF-8 chars, not NULL-terminated */
463         {
464             unsigned int strLen;
465 
466             if (eventDataLen < 4)
467                 return -1;
468             strLen = get4LE(eventData);
469             eventData += 4;
470             eventDataLen -= 4;
471 
472             if (eventDataLen < strLen)
473                 return -1;
474 
475             if (strLen < outBufLen) {
476                 memcpy(outBuf, eventData, strLen);
477                 outBuf += strLen;
478                 outBufLen -= strLen;
479             } else if (outBufLen > 0) {
480                 /* copy what we can */
481                 memcpy(outBuf, eventData, outBufLen);
482                 outBuf += outBufLen;
483                 outBufLen -= outBufLen;
484                 goto no_room;
485             }
486             eventData += strLen;
487             eventDataLen -= strLen;
488             break;
489         }
490     case EVENT_TYPE_LIST:
491         /* N items, all different types */
492         {
493             unsigned char count;
494             int i;
495 
496             if (eventDataLen < 1)
497                 return -1;
498 
499             count = *eventData++;
500             eventDataLen--;
501 
502             if (outBufLen > 0) {
503                 *outBuf++ = '[';
504                 outBufLen--;
505             } else {
506                 goto no_room;
507             }
508 
509             for (i = 0; i < count; i++) {
510                 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
511                         &outBuf, &outBufLen);
512                 if (result != 0)
513                     goto bail;
514 
515                 if (i < count-1) {
516                     if (outBufLen > 0) {
517                         *outBuf++ = ',';
518                         outBufLen--;
519                     } else {
520                         goto no_room;
521                     }
522                 }
523             }
524 
525             if (outBufLen > 0) {
526                 *outBuf++ = ']';
527                 outBufLen--;
528             } else {
529                 goto no_room;
530             }
531         }
532         break;
533     default:
534         fprintf(stderr, "Unknown binary event type %d\n", type);
535         return -1;
536     }
537 
538 bail:
539     *pEventData = eventData;
540     *pEventDataLen = eventDataLen;
541     *pOutBuf = outBuf;
542     *pOutBufLen = outBufLen;
543     return result;
544 
545 no_room:
546     result = 1;
547     goto bail;
548 }
549 
550 /**
551  * Convert a binary log entry to ASCII form.
552  *
553  * For convenience we mimic the processLogBuffer API.  There is no
554  * pre-defined output length for the binary data, since we're free to format
555  * it however we choose, which means we can't really use a fixed-size buffer
556  * here.
557  */
android_log_processBinaryLogBuffer(struct logger_entry * buf,AndroidLogEntry * entry,const EventTagMap * map,char * messageBuf,int messageBufLen)558 int android_log_processBinaryLogBuffer(struct logger_entry *buf,
559     AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
560     int messageBufLen)
561 {
562     size_t inCount;
563     unsigned int tagIndex;
564     const unsigned char* eventData;
565 
566     entry->tv_sec = buf->sec;
567     entry->tv_nsec = buf->nsec;
568     entry->priority = ANDROID_LOG_INFO;
569     entry->pid = buf->pid;
570     entry->tid = buf->tid;
571 
572     /*
573      * Pull the tag out.
574      */
575     eventData = (const unsigned char*) buf->msg;
576     inCount = buf->len;
577     if (inCount < 4)
578         return -1;
579     tagIndex = get4LE(eventData);
580     eventData += 4;
581     inCount -= 4;
582 
583     if (map != NULL) {
584         entry->tag = android_lookupEventTag(map, tagIndex);
585     } else {
586         entry->tag = NULL;
587     }
588 
589     /*
590      * If we don't have a map, or didn't find the tag number in the map,
591      * stuff a generated tag value into the start of the output buffer and
592      * shift the buffer pointers down.
593      */
594     if (entry->tag == NULL) {
595         int tagLen;
596 
597         tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
598         entry->tag = messageBuf;
599         messageBuf += tagLen+1;
600         messageBufLen -= tagLen+1;
601     }
602 
603     /*
604      * Format the event log data into the buffer.
605      */
606     char* outBuf = messageBuf;
607     size_t outRemaining = messageBufLen-1;      /* leave one for nul byte */
608     int result;
609     result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
610                 &outRemaining);
611     if (result < 0) {
612         fprintf(stderr, "Binary log entry conversion failed\n");
613         return -1;
614     } else if (result == 1) {
615         if (outBuf > messageBuf) {
616             /* leave an indicator */
617             *(outBuf-1) = '!';
618         } else {
619             /* no room to output anything at all */
620             *outBuf++ = '!';
621             outRemaining--;
622         }
623         /* pretend we ate all the data */
624         inCount = 0;
625     }
626 
627     /* eat the silly terminating '\n' */
628     if (inCount == 1 && *eventData == '\n') {
629         eventData++;
630         inCount--;
631     }
632 
633     if (inCount != 0) {
634         fprintf(stderr,
635             "Warning: leftover binary log data (%d bytes)\n", inCount);
636     }
637 
638     /*
639      * Terminate the buffer.  The NUL byte does not count as part of
640      * entry->messageLen.
641      */
642     *outBuf = '\0';
643     entry->messageLen = outBuf - messageBuf;
644     assert(entry->messageLen == (messageBufLen-1) - outRemaining);
645 
646     entry->message = messageBuf;
647 
648     return 0;
649 }
650 
651 /**
652  * Formats a log message into a buffer
653  *
654  * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
655  * If return value != defaultBuffer, caller must call free()
656  * Returns NULL on malloc error
657  */
658 
android_log_formatLogLine(AndroidLogFormat * p_format,char * defaultBuffer,size_t defaultBufferSize,const AndroidLogEntry * entry,size_t * p_outLength)659 char *android_log_formatLogLine (
660     AndroidLogFormat *p_format,
661     char *defaultBuffer,
662     size_t defaultBufferSize,
663     const AndroidLogEntry *entry,
664     size_t *p_outLength)
665 {
666 #if defined(HAVE_LOCALTIME_R)
667     struct tm tmBuf;
668 #endif
669     struct tm* ptm;
670     char timeBuf[32];
671     char headerBuf[128];
672     char prefixBuf[128], suffixBuf[128];
673     char priChar;
674     int prefixSuffixIsHeaderFooter = 0;
675     char * ret = NULL;
676 
677     priChar = filterPriToChar(entry->priority);
678 
679     /*
680      * Get the current date/time in pretty form
681      *
682      * It's often useful when examining a log with "less" to jump to
683      * a specific point in the file by searching for the date/time stamp.
684      * For this reason it's very annoying to have regexp meta characters
685      * in the time stamp.  Don't use forward slashes, parenthesis,
686      * brackets, asterisks, or other special chars here.
687      */
688 #if defined(HAVE_LOCALTIME_R)
689     ptm = localtime_r(&(entry->tv_sec), &tmBuf);
690 #else
691     ptm = localtime(&(entry->tv_sec));
692 #endif
693     //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
694     strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
695 
696     /*
697      * Construct a buffer containing the log header and log message.
698      */
699     size_t prefixLen, suffixLen;
700 
701     switch (p_format->format) {
702         case FORMAT_TAG:
703             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
704                 "%c/%-8s: ", priChar, entry->tag);
705             strcpy(suffixBuf, "\n"); suffixLen = 1;
706             break;
707         case FORMAT_PROCESS:
708             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
709                 "%c(%5d) ", priChar, entry->pid);
710             suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
711                 "  (%s)\n", entry->tag);
712             break;
713         case FORMAT_THREAD:
714             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
715                 "%c(%5d:%p) ", priChar, entry->pid, (void*)entry->tid);
716             strcpy(suffixBuf, "\n");
717             suffixLen = 1;
718             break;
719         case FORMAT_RAW:
720             prefixBuf[0] = 0;
721             prefixLen = 0;
722             strcpy(suffixBuf, "\n");
723             suffixLen = 1;
724             break;
725         case FORMAT_TIME:
726             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
727                 "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
728                 priChar, entry->tag, entry->pid);
729             strcpy(suffixBuf, "\n");
730             suffixLen = 1;
731             break;
732         case FORMAT_THREADTIME:
733             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
734                 "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
735                 (int)entry->pid, (int)entry->tid, priChar, entry->tag);
736             strcpy(suffixBuf, "\n");
737             suffixLen = 1;
738             break;
739         case FORMAT_LONG:
740             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
741                 "[ %s.%03ld %5d:%p %c/%-8s ]\n",
742                 timeBuf, entry->tv_nsec / 1000000, entry->pid,
743                 (void*)entry->tid, priChar, entry->tag);
744             strcpy(suffixBuf, "\n\n");
745             suffixLen = 2;
746             prefixSuffixIsHeaderFooter = 1;
747             break;
748         case FORMAT_BRIEF:
749         default:
750             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
751                 "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
752             strcpy(suffixBuf, "\n");
753             suffixLen = 1;
754             break;
755     }
756     /* snprintf has a weird return value.   It returns what would have been
757      * written given a large enough buffer.  In the case that the prefix is
758      * longer then our buffer(128), it messes up the calculations below
759      * possibly causing heap corruption.  To avoid this we double check and
760      * set the length at the maximum (size minus null byte)
761      */
762     if(prefixLen >= sizeof(prefixBuf))
763         prefixLen = sizeof(prefixBuf) - 1;
764     if(suffixLen >= sizeof(suffixBuf))
765         suffixLen = sizeof(suffixBuf) - 1;
766 
767     /* the following code is tragically unreadable */
768 
769     size_t numLines;
770     size_t i;
771     char *p;
772     size_t bufferSize;
773     const char *pm;
774 
775     if (prefixSuffixIsHeaderFooter) {
776         // we're just wrapping message with a header/footer
777         numLines = 1;
778     } else {
779         pm = entry->message;
780         numLines = 0;
781 
782         // The line-end finding here must match the line-end finding
783         // in for ( ... numLines...) loop below
784         while (pm < (entry->message + entry->messageLen)) {
785             if (*pm++ == '\n') numLines++;
786         }
787         // plus one line for anything not newline-terminated at the end
788         if (pm > entry->message && *(pm-1) != '\n') numLines++;
789     }
790 
791     // this is an upper bound--newlines in message may be counted
792     // extraneously
793     bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
794 
795     if (defaultBufferSize >= bufferSize) {
796         ret = defaultBuffer;
797     } else {
798         ret = (char *)malloc(bufferSize);
799 
800         if (ret == NULL) {
801             return ret;
802         }
803     }
804 
805     ret[0] = '\0';       /* to start strcat off */
806 
807     p = ret;
808     pm = entry->message;
809 
810     if (prefixSuffixIsHeaderFooter) {
811         strcat(p, prefixBuf);
812         p += prefixLen;
813         strncat(p, entry->message, entry->messageLen);
814         p += entry->messageLen;
815         strcat(p, suffixBuf);
816         p += suffixLen;
817     } else {
818         while(pm < (entry->message + entry->messageLen)) {
819             const char *lineStart;
820             size_t lineLen;
821 
822             lineStart = pm;
823 
824             // Find the next end-of-line in message
825             while (pm < (entry->message + entry->messageLen)
826                     && *pm != '\n') pm++;
827             lineLen = pm - lineStart;
828 
829             strcat(p, prefixBuf);
830             p += prefixLen;
831             strncat(p, lineStart, lineLen);
832             p += lineLen;
833             strcat(p, suffixBuf);
834             p += suffixLen;
835 
836             if (*pm == '\n') pm++;
837         }
838     }
839 
840     if (p_outLength != NULL) {
841         *p_outLength = p - ret;
842     }
843 
844     return ret;
845 }
846 
847 /**
848  * Either print or do not print log line, based on filter
849  *
850  * Returns count bytes written
851  */
852 
android_log_printLogLine(AndroidLogFormat * p_format,int fd,const AndroidLogEntry * entry)853 int android_log_printLogLine(
854     AndroidLogFormat *p_format,
855     int fd,
856     const AndroidLogEntry *entry)
857 {
858     int ret;
859     char defaultBuffer[512];
860     char *outBuffer = NULL;
861     size_t totalLen;
862 
863     outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
864             sizeof(defaultBuffer), entry, &totalLen);
865 
866     if (!outBuffer)
867         return -1;
868 
869     do {
870         ret = write(fd, outBuffer, totalLen);
871     } while (ret < 0 && errno == EINTR);
872 
873     if (ret < 0) {
874         fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
875         ret = 0;
876         goto done;
877     }
878 
879     if (((size_t)ret) < totalLen) {
880         fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
881                 (int)totalLen);
882         goto done;
883     }
884 
885 done:
886     if (outBuffer != defaultBuffer) {
887         free(outBuffer);
888     }
889 
890     return ret;
891 }
892 
893 
894 
logprint_run_tests()895 void logprint_run_tests()
896 {
897 #if 0
898 
899     fprintf(stderr, "tests disabled\n");
900 
901 #else
902 
903     int err;
904     const char *tag;
905     AndroidLogFormat *p_format;
906 
907     p_format = android_log_format_new();
908 
909     fprintf(stderr, "running tests\n");
910 
911     tag = "random";
912 
913     android_log_addFilterRule(p_format,"*:i");
914 
915     assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
916     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
917     android_log_addFilterRule(p_format, "*");
918     assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
919     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
920     android_log_addFilterRule(p_format, "*:v");
921     assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
922     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
923     android_log_addFilterRule(p_format, "*:i");
924     assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
925     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
926 
927     android_log_addFilterRule(p_format, "random");
928     assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
929     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
930     android_log_addFilterRule(p_format, "random:v");
931     assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
932     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
933     android_log_addFilterRule(p_format, "random:d");
934     assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
935     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
936     android_log_addFilterRule(p_format, "random:w");
937     assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
938     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
939 
940     android_log_addFilterRule(p_format, "crap:*");
941     assert (ANDROID_LOG_VERBOSE== filterPriForTag(p_format, "crap"));
942     assert(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
943 
944     // invalid expression
945     err = android_log_addFilterRule(p_format, "random:z");
946     assert (err < 0);
947     assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
948     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
949 
950     // Issue #550946
951     err = android_log_addFilterString(p_format, " ");
952     assert(err == 0);
953     assert(ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
954 
955     // note trailing space
956     err = android_log_addFilterString(p_format, "*:s random:d ");
957     assert(err == 0);
958     assert(ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
959 
960     err = android_log_addFilterString(p_format, "*:s random:z");
961     assert(err < 0);
962 
963 
964 #if 0
965     char *ret;
966     char defaultBuffer[512];
967 
968     ret = android_log_formatLogLine(p_format,
969         defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
970         123, 123, "random", "nofile", strlen("Hello"), "Hello", NULL);
971 #endif
972 
973 
974     fprintf(stderr, "tests complete\n");
975 #endif
976 }
977