logprint.c revision d2c8f52189f8c2a13b88a107c6495f9d83196d2d
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
32typedef struct FilterInfo_t {
33    char *mTag;
34    android_LogPriority mPri;
35    struct FilterInfo_t *p_next;
36} FilterInfo;
37
38struct AndroidLogFormat_t {
39    android_LogPriority global_pri;
40    FilterInfo *filters;
41    AndroidLogPrintFormat format;
42};
43
44static 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
55static 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 */
69static 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
104static 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
121static 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 */
143static 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 */
163int android_log_shouldPrintLine (
164        AndroidLogFormat *p_format, const char *tag, android_LogPriority pri)
165{
166    return pri >= filterPriForTag(p_format, tag);
167}
168
169AndroidLogFormat *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
181void 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
199void 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 */
208AndroidLogPrintFormat 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
234int 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;
291error:
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
307int 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;
329error:
330    free (filterStringCopy);
331    return -1;
332}
333
334static 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 */
350int 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 */
412static 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 */
420static 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 */
441static 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
579bail:
580    *pEventData = eventData;
581    *pEventDataLen = eventDataLen;
582    *pOutBuf = outBuf;
583    *pOutBufLen = outBufLen;
584    return result;
585
586no_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 */
599int 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
700char *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
893int 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
925done:
926    if (outBuffer != defaultBuffer) {
927        free(outBuffer);
928    }
929
930    return ret;
931}
932
933
934
935void 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