• 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     entry->tv_sec = buf->sec;
354     entry->tv_nsec = buf->nsec;
355     entry->pid = buf->pid;
356     entry->tid = buf->tid;
357 
358     /*
359      * format: <priority:1><tag:N>\0<message:N>\0
360      *
361      * tag str
362      *   starts at buf->msg+1
363      * msg
364      *   starts at buf->msg+1+len(tag)+1
365      *
366      * The message may have been truncated by the kernel log driver.
367      * When that happens, we must null-terminate the message ourselves.
368      */
369     if (buf->len < 3) {
370         // An well-formed entry must consist of at least a priority
371         // and two null characters
372         fprintf(stderr, "+++ LOG: entry too small\n");
373         return -1;
374     }
375 
376     int msgStart = -1;
377     int msgEnd = -1;
378 
379     int i;
380     for (i = 1; i < buf->len; i++) {
381         if (buf->msg[i] == '\0') {
382             if (msgStart == -1) {
383                 msgStart = i + 1;
384             } else {
385                 msgEnd = i;
386                 break;
387             }
388         }
389     }
390 
391     if (msgStart == -1) {
392         fprintf(stderr, "+++ LOG: malformed log message\n");
393         return -1;
394     }
395     if (msgEnd == -1) {
396         // incoming message not null-terminated; force it
397         msgEnd = buf->len - 1;
398         buf->msg[msgEnd] = '\0';
399     }
400 
401     entry->priority = buf->msg[0];
402     entry->tag = buf->msg + 1;
403     entry->message = buf->msg + msgStart;
404     entry->messageLen = msgEnd - msgStart;
405 
406     return 0;
407 }
408 
409 /*
410  * Extract a 4-byte value from a byte stream.
411  */
get4LE(const uint8_t * src)412 static inline uint32_t get4LE(const uint8_t* src)
413 {
414     return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
415 }
416 
417 /*
418  * Extract an 8-byte value from a byte stream.
419  */
get8LE(const uint8_t * src)420 static inline uint64_t get8LE(const uint8_t* src)
421 {
422     uint32_t low, high;
423 
424     low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
425     high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
426     return ((long long) high << 32) | (long long) low;
427 }
428 
429 
430 /*
431  * Recursively convert binary log data to printable form.
432  *
433  * This needs to be recursive because you can have lists of lists.
434  *
435  * If we run out of room, we stop processing immediately.  It's important
436  * for us to check for space on every output element to avoid producing
437  * garbled output.
438  *
439  * Returns 0 on success, 1 on buffer full, -1 on failure.
440  */
android_log_printBinaryEvent(const unsigned char ** pEventData,size_t * pEventDataLen,char ** pOutBuf,size_t * pOutBufLen)441 static int android_log_printBinaryEvent(const unsigned char** pEventData,
442     size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
443 {
444     const unsigned char* eventData = *pEventData;
445     size_t eventDataLen = *pEventDataLen;
446     char* outBuf = *pOutBuf;
447     size_t outBufLen = *pOutBufLen;
448     unsigned char type;
449     size_t outCount;
450     int result = 0;
451 
452     if (eventDataLen < 1)
453         return -1;
454     type = *eventData++;
455     eventDataLen--;
456 
457     //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
458 
459     switch (type) {
460     case EVENT_TYPE_INT:
461         /* 32-bit signed int */
462         {
463             int ival;
464 
465             if (eventDataLen < 4)
466                 return -1;
467             ival = get4LE(eventData);
468             eventData += 4;
469             eventDataLen -= 4;
470 
471             outCount = snprintf(outBuf, outBufLen, "%d", ival);
472             if (outCount < outBufLen) {
473                 outBuf += outCount;
474                 outBufLen -= outCount;
475             } else {
476                 /* halt output */
477                 goto no_room;
478             }
479         }
480         break;
481     case EVENT_TYPE_LONG:
482         /* 64-bit signed long */
483         {
484             long long lval;
485 
486             if (eventDataLen < 8)
487                 return -1;
488             lval = get8LE(eventData);
489             eventData += 8;
490             eventDataLen -= 8;
491 
492             outCount = snprintf(outBuf, outBufLen, "%lld", lval);
493             if (outCount < outBufLen) {
494                 outBuf += outCount;
495                 outBufLen -= outCount;
496             } else {
497                 /* halt output */
498                 goto no_room;
499             }
500         }
501         break;
502     case EVENT_TYPE_STRING:
503         /* UTF-8 chars, not NULL-terminated */
504         {
505             unsigned int strLen;
506 
507             if (eventDataLen < 4)
508                 return -1;
509             strLen = get4LE(eventData);
510             eventData += 4;
511             eventDataLen -= 4;
512 
513             if (eventDataLen < strLen)
514                 return -1;
515 
516             if (strLen < outBufLen) {
517                 memcpy(outBuf, eventData, strLen);
518                 outBuf += strLen;
519                 outBufLen -= strLen;
520             } else if (outBufLen > 0) {
521                 /* copy what we can */
522                 memcpy(outBuf, eventData, outBufLen);
523                 outBuf += outBufLen;
524                 outBufLen -= outBufLen;
525                 goto no_room;
526             }
527             eventData += strLen;
528             eventDataLen -= strLen;
529             break;
530         }
531     case EVENT_TYPE_LIST:
532         /* N items, all different types */
533         {
534             unsigned char count;
535             int i;
536 
537             if (eventDataLen < 1)
538                 return -1;
539 
540             count = *eventData++;
541             eventDataLen--;
542 
543             if (outBufLen > 0) {
544                 *outBuf++ = '[';
545                 outBufLen--;
546             } else {
547                 goto no_room;
548             }
549 
550             for (i = 0; i < count; i++) {
551                 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
552                         &outBuf, &outBufLen);
553                 if (result != 0)
554                     goto bail;
555 
556                 if (i < count-1) {
557                     if (outBufLen > 0) {
558                         *outBuf++ = ',';
559                         outBufLen--;
560                     } else {
561                         goto no_room;
562                     }
563                 }
564             }
565 
566             if (outBufLen > 0) {
567                 *outBuf++ = ']';
568                 outBufLen--;
569             } else {
570                 goto no_room;
571             }
572         }
573         break;
574     default:
575         fprintf(stderr, "Unknown binary event type %d\n", type);
576         return -1;
577     }
578 
579 bail:
580     *pEventData = eventData;
581     *pEventDataLen = eventDataLen;
582     *pOutBuf = outBuf;
583     *pOutBufLen = outBufLen;
584     return result;
585 
586 no_room:
587     result = 1;
588     goto bail;
589 }
590 
591 /**
592  * Convert a binary log entry to ASCII form.
593  *
594  * For convenience we mimic the processLogBuffer API.  There is no
595  * pre-defined output length for the binary data, since we're free to format
596  * it however we choose, which means we can't really use a fixed-size buffer
597  * here.
598  */
android_log_processBinaryLogBuffer(struct logger_entry * buf,AndroidLogEntry * entry,const EventTagMap * map,char * messageBuf,int messageBufLen)599 int android_log_processBinaryLogBuffer(struct logger_entry *buf,
600     AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
601     int messageBufLen)
602 {
603     size_t inCount;
604     unsigned int tagIndex;
605     const unsigned char* eventData;
606 
607     entry->tv_sec = buf->sec;
608     entry->tv_nsec = buf->nsec;
609     entry->priority = ANDROID_LOG_INFO;
610     entry->pid = buf->pid;
611     entry->tid = buf->tid;
612 
613     /*
614      * Pull the tag out.
615      */
616     eventData = (const unsigned char*) buf->msg;
617     inCount = buf->len;
618     if (inCount < 4)
619         return -1;
620     tagIndex = get4LE(eventData);
621     eventData += 4;
622     inCount -= 4;
623 
624     if (map != NULL) {
625         entry->tag = android_lookupEventTag(map, tagIndex);
626     } else {
627         entry->tag = NULL;
628     }
629 
630     /*
631      * If we don't have a map, or didn't find the tag number in the map,
632      * stuff a generated tag value into the start of the output buffer and
633      * shift the buffer pointers down.
634      */
635     if (entry->tag == NULL) {
636         int tagLen;
637 
638         tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
639         entry->tag = messageBuf;
640         messageBuf += tagLen+1;
641         messageBufLen -= tagLen+1;
642     }
643 
644     /*
645      * Format the event log data into the buffer.
646      */
647     char* outBuf = messageBuf;
648     size_t outRemaining = messageBufLen-1;      /* leave one for nul byte */
649     int result;
650     result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
651                 &outRemaining);
652     if (result < 0) {
653         fprintf(stderr, "Binary log entry conversion failed\n");
654         return -1;
655     } else if (result == 1) {
656         if (outBuf > messageBuf) {
657             /* leave an indicator */
658             *(outBuf-1) = '!';
659         } else {
660             /* no room to output anything at all */
661             *outBuf++ = '!';
662             outRemaining--;
663         }
664         /* pretend we ate all the data */
665         inCount = 0;
666     }
667 
668     /* eat the silly terminating '\n' */
669     if (inCount == 1 && *eventData == '\n') {
670         eventData++;
671         inCount--;
672     }
673 
674     if (inCount != 0) {
675         fprintf(stderr,
676             "Warning: leftover binary log data (%zu bytes)\n", inCount);
677     }
678 
679     /*
680      * Terminate the buffer.  The NUL byte does not count as part of
681      * entry->messageLen.
682      */
683     *outBuf = '\0';
684     entry->messageLen = outBuf - messageBuf;
685     assert(entry->messageLen == (messageBufLen-1) - outRemaining);
686 
687     entry->message = messageBuf;
688 
689     return 0;
690 }
691 
692 /**
693  * Formats a log message into a buffer
694  *
695  * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
696  * If return value != defaultBuffer, caller must call free()
697  * Returns NULL on malloc error
698  */
699 
android_log_formatLogLine(AndroidLogFormat * p_format,char * defaultBuffer,size_t defaultBufferSize,const AndroidLogEntry * entry,size_t * p_outLength)700 char *android_log_formatLogLine (
701     AndroidLogFormat *p_format,
702     char *defaultBuffer,
703     size_t defaultBufferSize,
704     const AndroidLogEntry *entry,
705     size_t *p_outLength)
706 {
707 #if defined(HAVE_LOCALTIME_R)
708     struct tm tmBuf;
709 #endif
710     struct tm* ptm;
711     char timeBuf[32];
712     char headerBuf[128];
713     char prefixBuf[128], suffixBuf[128];
714     char priChar;
715     int prefixSuffixIsHeaderFooter = 0;
716     char * ret = NULL;
717 
718     priChar = filterPriToChar(entry->priority);
719 
720     /*
721      * Get the current date/time in pretty form
722      *
723      * It's often useful when examining a log with "less" to jump to
724      * a specific point in the file by searching for the date/time stamp.
725      * For this reason it's very annoying to have regexp meta characters
726      * in the time stamp.  Don't use forward slashes, parenthesis,
727      * brackets, asterisks, or other special chars here.
728      */
729 #if defined(HAVE_LOCALTIME_R)
730     ptm = localtime_r(&(entry->tv_sec), &tmBuf);
731 #else
732     ptm = localtime(&(entry->tv_sec));
733 #endif
734     //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
735     strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
736 
737     /*
738      * Construct a buffer containing the log header and log message.
739      */
740     size_t prefixLen, suffixLen;
741 
742     switch (p_format->format) {
743         case FORMAT_TAG:
744             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
745                 "%c/%-8s: ", priChar, entry->tag);
746             strcpy(suffixBuf, "\n"); suffixLen = 1;
747             break;
748         case FORMAT_PROCESS:
749             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
750                 "%c(%5d) ", priChar, entry->pid);
751             suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
752                 "  (%s)\n", entry->tag);
753             break;
754         case FORMAT_THREAD:
755             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
756                 "%c(%5d:%5d) ", priChar, entry->pid, entry->tid);
757             strcpy(suffixBuf, "\n");
758             suffixLen = 1;
759             break;
760         case FORMAT_RAW:
761             prefixBuf[0] = 0;
762             prefixLen = 0;
763             strcpy(suffixBuf, "\n");
764             suffixLen = 1;
765             break;
766         case FORMAT_TIME:
767             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
768                 "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
769                 priChar, entry->tag, entry->pid);
770             strcpy(suffixBuf, "\n");
771             suffixLen = 1;
772             break;
773         case FORMAT_THREADTIME:
774             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
775                 "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
776                 entry->pid, entry->tid, priChar, entry->tag);
777             strcpy(suffixBuf, "\n");
778             suffixLen = 1;
779             break;
780         case FORMAT_LONG:
781             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
782                 "[ %s.%03ld %5d:%5d %c/%-8s ]\n",
783                 timeBuf, entry->tv_nsec / 1000000, entry->pid,
784                 entry->tid, priChar, entry->tag);
785             strcpy(suffixBuf, "\n\n");
786             suffixLen = 2;
787             prefixSuffixIsHeaderFooter = 1;
788             break;
789         case FORMAT_BRIEF:
790         default:
791             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
792                 "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
793             strcpy(suffixBuf, "\n");
794             suffixLen = 1;
795             break;
796     }
797     /* snprintf has a weird return value.   It returns what would have been
798      * written given a large enough buffer.  In the case that the prefix is
799      * longer then our buffer(128), it messes up the calculations below
800      * possibly causing heap corruption.  To avoid this we double check and
801      * set the length at the maximum (size minus null byte)
802      */
803     if(prefixLen >= sizeof(prefixBuf))
804         prefixLen = sizeof(prefixBuf) - 1;
805     if(suffixLen >= sizeof(suffixBuf))
806         suffixLen = sizeof(suffixBuf) - 1;
807 
808     /* the following code is tragically unreadable */
809 
810     size_t numLines;
811     size_t i;
812     char *p;
813     size_t bufferSize;
814     const char *pm;
815 
816     if (prefixSuffixIsHeaderFooter) {
817         // we're just wrapping message with a header/footer
818         numLines = 1;
819     } else {
820         pm = entry->message;
821         numLines = 0;
822 
823         // The line-end finding here must match the line-end finding
824         // in for ( ... numLines...) loop below
825         while (pm < (entry->message + entry->messageLen)) {
826             if (*pm++ == '\n') numLines++;
827         }
828         // plus one line for anything not newline-terminated at the end
829         if (pm > entry->message && *(pm-1) != '\n') numLines++;
830     }
831 
832     // this is an upper bound--newlines in message may be counted
833     // extraneously
834     bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
835 
836     if (defaultBufferSize >= bufferSize) {
837         ret = defaultBuffer;
838     } else {
839         ret = (char *)malloc(bufferSize);
840 
841         if (ret == NULL) {
842             return ret;
843         }
844     }
845 
846     ret[0] = '\0';       /* to start strcat off */
847 
848     p = ret;
849     pm = entry->message;
850 
851     if (prefixSuffixIsHeaderFooter) {
852         strcat(p, prefixBuf);
853         p += prefixLen;
854         strncat(p, entry->message, entry->messageLen);
855         p += entry->messageLen;
856         strcat(p, suffixBuf);
857         p += suffixLen;
858     } else {
859         while(pm < (entry->message + entry->messageLen)) {
860             const char *lineStart;
861             size_t lineLen;
862             lineStart = pm;
863 
864             // Find the next end-of-line in message
865             while (pm < (entry->message + entry->messageLen)
866                     && *pm != '\n') pm++;
867             lineLen = pm - lineStart;
868 
869             strcat(p, prefixBuf);
870             p += prefixLen;
871             strncat(p, lineStart, lineLen);
872             p += lineLen;
873             strcat(p, suffixBuf);
874             p += suffixLen;
875 
876             if (*pm == '\n') pm++;
877         }
878     }
879 
880     if (p_outLength != NULL) {
881         *p_outLength = p - ret;
882     }
883 
884     return ret;
885 }
886 
887 /**
888  * Either print or do not print log line, based on filter
889  *
890  * Returns count bytes written
891  */
892 
android_log_printLogLine(AndroidLogFormat * p_format,int fd,const AndroidLogEntry * entry)893 int android_log_printLogLine(
894     AndroidLogFormat *p_format,
895     int fd,
896     const AndroidLogEntry *entry)
897 {
898     int ret;
899     char defaultBuffer[512];
900     char *outBuffer = NULL;
901     size_t totalLen;
902 
903     outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
904             sizeof(defaultBuffer), entry, &totalLen);
905 
906     if (!outBuffer)
907         return -1;
908 
909     do {
910         ret = write(fd, outBuffer, totalLen);
911     } while (ret < 0 && errno == EINTR);
912 
913     if (ret < 0) {
914         fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
915         ret = 0;
916         goto done;
917     }
918 
919     if (((size_t)ret) < totalLen) {
920         fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
921                 (int)totalLen);
922         goto done;
923     }
924 
925 done:
926     if (outBuffer != defaultBuffer) {
927         free(outBuffer);
928     }
929 
930     return ret;
931 }
932 
933 
934 
logprint_run_tests()935 void logprint_run_tests()
936 {
937 #if 0
938 
939     fprintf(stderr, "tests disabled\n");
940 
941 #else
942 
943     int err;
944     const char *tag;
945     AndroidLogFormat *p_format;
946 
947     p_format = android_log_format_new();
948 
949     fprintf(stderr, "running tests\n");
950 
951     tag = "random";
952 
953     android_log_addFilterRule(p_format,"*:i");
954 
955     assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
956     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
957     android_log_addFilterRule(p_format, "*");
958     assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
959     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
960     android_log_addFilterRule(p_format, "*:v");
961     assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
962     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
963     android_log_addFilterRule(p_format, "*:i");
964     assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
965     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
966 
967     android_log_addFilterRule(p_format, "random");
968     assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
969     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
970     android_log_addFilterRule(p_format, "random:v");
971     assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
972     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
973     android_log_addFilterRule(p_format, "random:d");
974     assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
975     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
976     android_log_addFilterRule(p_format, "random:w");
977     assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
978     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
979 
980     android_log_addFilterRule(p_format, "crap:*");
981     assert (ANDROID_LOG_VERBOSE== filterPriForTag(p_format, "crap"));
982     assert(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
983 
984     // invalid expression
985     err = android_log_addFilterRule(p_format, "random:z");
986     assert (err < 0);
987     assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
988     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
989 
990     // Issue #550946
991     err = android_log_addFilterString(p_format, " ");
992     assert(err == 0);
993     assert(ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
994 
995     // note trailing space
996     err = android_log_addFilterString(p_format, "*:s random:d ");
997     assert(err == 0);
998     assert(ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
999 
1000     err = android_log_addFilterString(p_format, "*:s random:z");
1001     assert(err < 0);
1002 
1003 
1004 #if 0
1005     char *ret;
1006     char defaultBuffer[512];
1007 
1008     ret = android_log_formatLogLine(p_format,
1009         defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
1010         123, 123, "random", "nofile", strlen("Hello"), "Hello", NULL);
1011 #endif
1012 
1013 
1014     fprintf(stderr, "tests complete\n");
1015 #endif
1016 }
1017