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