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 <log/logd.h> 30 #include <log/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 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 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 */ 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 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 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 */ 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 */ 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 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 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 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 */ 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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