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