1 /* 2 * Copyright (C) 2006-2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <arpa/inet.h> 18 #include <assert.h> 19 #include <ctype.h> 20 #include <dirent.h> 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <math.h> 24 #include <pthread.h> 25 #include <sched.h> 26 #include <stdarg.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <sys/cdefs.h> 31 #include <sys/resource.h> 32 #include <sys/socket.h> 33 #include <sys/stat.h> 34 #include <sys/types.h> 35 #include <time.h> 36 #include <unistd.h> 37 38 #include <atomic> 39 #include <memory> 40 #include <string> 41 #include <vector> 42 43 #include <android-base/file.h> 44 #include <android-base/properties.h> 45 #include <android-base/stringprintf.h> 46 #include <android-base/strings.h> 47 #include <cutils/sched_policy.h> 48 #include <cutils/sockets.h> 49 #include <log/event_tag_map.h> 50 #include <log/getopt.h> 51 #include <log/logcat.h> 52 #include <log/logprint.h> 53 #include <private/android_logger.h> 54 #include <system/thread_defs.h> 55 56 #include <pcrecpp.h> 57 58 #define DEFAULT_MAX_ROTATED_LOGS 4 59 60 struct log_device_t { 61 const char* device; 62 bool binary; 63 struct logger* logger; 64 struct logger_list* logger_list; 65 bool printed; 66 67 log_device_t* next; 68 69 log_device_t(const char* d, bool b) { 70 device = d; 71 binary = b; 72 next = nullptr; 73 printed = false; 74 logger = nullptr; 75 logger_list = nullptr; 76 } 77 }; 78 79 struct android_logcat_context_internal { 80 // status 81 volatile std::atomic_int retval; // valid if thread_stopped set 82 // Arguments passed in, or copies and storage thereof if a thread. 83 int argc; 84 char* const* argv; 85 char* const* envp; 86 std::vector<std::string> args; 87 std::vector<const char*> argv_hold; 88 std::vector<std::string> envs; 89 std::vector<const char*> envp_hold; 90 int output_fd; // duplication of fileno(output) (below) 91 int error_fd; // duplication of fileno(error) (below) 92 93 // library 94 int fds[2]; // From popen call 95 FILE* output; // everything writes to fileno(output), buffer unused 96 FILE* error; // unless error == output. 97 pthread_t thr; 98 volatile std::atomic_bool stop; // quick exit flag 99 volatile std::atomic_bool thread_stopped; 100 bool stderr_null; // shell "2>/dev/null" 101 bool stderr_stdout; // shell "2>&1" 102 103 // global variables 104 AndroidLogFormat* logformat; 105 const char* outputFileName; 106 // 0 means "no log rotation" 107 size_t logRotateSizeKBytes; 108 // 0 means "unbounded" 109 size_t maxRotatedLogs; 110 size_t outByteCount; 111 int printBinary; 112 int devCount; // >1 means multiple 113 pcrecpp::RE* regex; 114 log_device_t* devices; 115 EventTagMap* eventTagMap; 116 // 0 means "infinite" 117 size_t maxCount; 118 size_t printCount; 119 120 bool printItAnyways; 121 bool debug; 122 bool hasOpenedEventTagMap; 123 }; 124 125 // Creates a context associated with this logcat instance 126 android_logcat_context create_android_logcat() { 127 android_logcat_context_internal* context; 128 129 context = (android_logcat_context_internal*)calloc( 130 1, sizeof(android_logcat_context_internal)); 131 if (!context) return nullptr; 132 133 context->fds[0] = -1; 134 context->fds[1] = -1; 135 context->output_fd = -1; 136 context->error_fd = -1; 137 context->maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; 138 139 context->argv_hold.clear(); 140 context->args.clear(); 141 context->envp_hold.clear(); 142 context->envs.clear(); 143 144 return (android_logcat_context)context; 145 } 146 147 // logd prefixes records with a length field 148 #define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t) 149 150 namespace android { 151 152 enum helpType { HELP_FALSE, HELP_TRUE, HELP_FORMAT }; 153 154 // if showHelp is set, newline required in fmt statement to transition to usage 155 static void logcat_panic(android_logcat_context_internal* context, 156 enum helpType showHelp, const char* fmt, ...) 157 __printflike(3, 4); 158 159 static int openLogFile(const char* pathname) { 160 return open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); 161 } 162 163 static void close_output(android_logcat_context_internal* context) { 164 // split output_from_error 165 if (context->error == context->output) { 166 context->output = nullptr; 167 context->output_fd = -1; 168 } 169 if (context->error && (context->output_fd == fileno(context->error))) { 170 context->output_fd = -1; 171 } 172 if (context->output_fd == context->error_fd) { 173 context->output_fd = -1; 174 } 175 // close output channel 176 if (context->output) { 177 if (context->output != stdout) { 178 if (context->output_fd == fileno(context->output)) { 179 context->output_fd = -1; 180 } 181 if (context->fds[1] == fileno(context->output)) { 182 context->fds[1] = -1; 183 } 184 fclose(context->output); 185 } 186 context->output = nullptr; 187 } 188 if (context->output_fd >= 0) { 189 if (context->output_fd != fileno(stdout)) { 190 if (context->fds[1] == context->output_fd) { 191 context->fds[1] = -1; 192 } 193 close(context->output_fd); 194 } 195 context->output_fd = -1; 196 } 197 } 198 199 static void close_error(android_logcat_context_internal* context) { 200 // split error_from_output 201 if (context->output == context->error) { 202 context->error = nullptr; 203 context->error_fd = -1; 204 } 205 if (context->output && (context->error_fd == fileno(context->output))) { 206 context->error_fd = -1; 207 } 208 if (context->error_fd == context->output_fd) { 209 context->error_fd = -1; 210 } 211 // close error channel 212 if (context->error) { 213 if ((context->error != stderr) && (context->error != stdout)) { 214 if (context->error_fd == fileno(context->error)) { 215 context->error_fd = -1; 216 } 217 if (context->fds[1] == fileno(context->error)) { 218 context->fds[1] = -1; 219 } 220 fclose(context->error); 221 } 222 context->error = nullptr; 223 } 224 if (context->error_fd >= 0) { 225 if ((context->error_fd != fileno(stdout)) && 226 (context->error_fd != fileno(stderr))) { 227 if (context->fds[1] == context->error_fd) context->fds[1] = -1; 228 close(context->error_fd); 229 } 230 context->error_fd = -1; 231 } 232 } 233 234 static void rotateLogs(android_logcat_context_internal* context) { 235 int err; 236 237 // Can't rotate logs if we're not outputting to a file 238 if (!context->outputFileName) return; 239 240 close_output(context); 241 242 // Compute the maximum number of digits needed to count up to 243 // maxRotatedLogs in decimal. eg: 244 // maxRotatedLogs == 30 245 // -> log10(30) == 1.477 246 // -> maxRotationCountDigits == 2 247 int maxRotationCountDigits = 248 (context->maxRotatedLogs > 0) 249 ? (int)(floor(log10(context->maxRotatedLogs) + 1)) 250 : 0; 251 252 for (int i = context->maxRotatedLogs; i > 0; i--) { 253 std::string file1 = android::base::StringPrintf( 254 "%s.%.*d", context->outputFileName, maxRotationCountDigits, i); 255 256 std::string file0; 257 if (!(i - 1)) { 258 file0 = android::base::StringPrintf("%s", context->outputFileName); 259 } else { 260 file0 = 261 android::base::StringPrintf("%s.%.*d", context->outputFileName, 262 maxRotationCountDigits, i - 1); 263 } 264 265 if (!file0.length() || !file1.length()) { 266 perror("while rotating log files"); 267 break; 268 } 269 270 err = rename(file0.c_str(), file1.c_str()); 271 272 if (err < 0 && errno != ENOENT) { 273 perror("while rotating log files"); 274 } 275 } 276 277 context->output_fd = openLogFile(context->outputFileName); 278 279 if (context->output_fd < 0) { 280 logcat_panic(context, HELP_FALSE, "couldn't open output file"); 281 return; 282 } 283 context->output = fdopen(context->output_fd, "web"); 284 if (!context->output) { 285 logcat_panic(context, HELP_FALSE, "couldn't fdopen output file"); 286 return; 287 } 288 if (context->stderr_stdout) { 289 close_error(context); 290 context->error = context->output; 291 context->error_fd = context->output_fd; 292 } 293 294 context->outByteCount = 0; 295 } 296 297 void printBinary(android_logcat_context_internal* context, struct log_msg* buf) { 298 size_t size = buf->len(); 299 300 TEMP_FAILURE_RETRY(write(context->output_fd, buf, size)); 301 } 302 303 static bool regexOk(android_logcat_context_internal* context, 304 const AndroidLogEntry& entry) { 305 if (!context->regex) return true; 306 307 std::string messageString(entry.message, entry.messageLen); 308 309 return context->regex->PartialMatch(messageString); 310 } 311 312 static void processBuffer(android_logcat_context_internal* context, 313 log_device_t* dev, struct log_msg* buf) { 314 int bytesWritten = 0; 315 int err; 316 AndroidLogEntry entry; 317 char binaryMsgBuf[1024]; 318 319 if (dev->binary) { 320 if (!context->eventTagMap && !context->hasOpenedEventTagMap) { 321 context->eventTagMap = android_openEventTagMap(nullptr); 322 context->hasOpenedEventTagMap = true; 323 } 324 err = android_log_processBinaryLogBuffer( 325 &buf->entry_v1, &entry, context->eventTagMap, binaryMsgBuf, 326 sizeof(binaryMsgBuf)); 327 // printf(">>> pri=%d len=%d msg='%s'\n", 328 // entry.priority, entry.messageLen, entry.message); 329 } else { 330 err = android_log_processLogBuffer(&buf->entry_v1, &entry); 331 } 332 if ((err < 0) && !context->debug) return; 333 334 if (android_log_shouldPrintLine( 335 context->logformat, std::string(entry.tag, entry.tagLen).c_str(), 336 entry.priority)) { 337 bool match = regexOk(context, entry); 338 339 context->printCount += match; 340 if (match || context->printItAnyways) { 341 bytesWritten = android_log_printLogLine(context->logformat, 342 context->output_fd, &entry); 343 344 if (bytesWritten < 0) { 345 logcat_panic(context, HELP_FALSE, "output error"); 346 return; 347 } 348 } 349 } 350 351 context->outByteCount += bytesWritten; 352 353 if (context->logRotateSizeKBytes > 0 && 354 (context->outByteCount / 1024) >= context->logRotateSizeKBytes) { 355 rotateLogs(context); 356 } 357 } 358 359 static void maybePrintStart(android_logcat_context_internal* context, 360 log_device_t* dev, bool printDividers) { 361 if (!dev->printed || printDividers) { 362 if (context->devCount > 1 && !context->printBinary) { 363 char buf[1024]; 364 snprintf(buf, sizeof(buf), "--------- %s %s\n", 365 dev->printed ? "switch to" : "beginning of", dev->device); 366 if (write(context->output_fd, buf, strlen(buf)) < 0) { 367 logcat_panic(context, HELP_FALSE, "output error"); 368 return; 369 } 370 } 371 dev->printed = true; 372 } 373 } 374 375 static void setupOutputAndSchedulingPolicy( 376 android_logcat_context_internal* context, bool blocking) { 377 if (!context->outputFileName) return; 378 379 if (blocking) { 380 // Lower priority and set to batch scheduling if we are saving 381 // the logs into files and taking continuous content. 382 if ((set_sched_policy(0, SP_BACKGROUND) < 0) && context->error) { 383 fprintf(context->error, 384 "failed to set background scheduling policy\n"); 385 } 386 387 struct sched_param param; 388 memset(¶m, 0, sizeof(param)); 389 if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) { 390 fprintf(stderr, "failed to set to batch scheduler\n"); 391 } 392 393 if ((setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) && 394 context->error) { 395 fprintf(context->error, "failed set to priority\n"); 396 } 397 } 398 399 close_output(context); 400 401 context->output_fd = openLogFile(context->outputFileName); 402 403 if (context->output_fd < 0) { 404 logcat_panic(context, HELP_FALSE, "couldn't open output file"); 405 return; 406 } 407 408 struct stat statbuf; 409 if (fstat(context->output_fd, &statbuf) == -1) { 410 close_output(context); 411 logcat_panic(context, HELP_FALSE, "couldn't get output file stat\n"); 412 return; 413 } 414 415 if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) { 416 close_output(context); 417 logcat_panic(context, HELP_FALSE, "invalid output file stat\n"); 418 return; 419 } 420 421 context->output = fdopen(context->output_fd, "web"); 422 423 context->outByteCount = statbuf.st_size; 424 } 425 426 // clang-format off 427 static void show_help(android_logcat_context_internal* context) { 428 if (!context->error) return; 429 430 const char* cmd = strrchr(context->argv[0], '/'); 431 cmd = cmd ? cmd + 1 : context->argv[0]; 432 433 fprintf(context->error, "Usage: %s [options] [filterspecs]\n", cmd); 434 435 fprintf(context->error, "options include:\n" 436 " -s Set default filter to silent. Equivalent to filterspec '*:S'\n" 437 " -f <file>, --file=<file> Log to file. Default is stdout\n" 438 " -r <kbytes>, --rotate-kbytes=<kbytes>\n" 439 " Rotate log every kbytes. Requires -f option\n" 440 " -n <count>, --rotate-count=<count>\n" 441 " Sets max number of rotated logs to <count>, default 4\n" 442 " --id=<id> If the signature id for logging to file changes, then clear\n" 443 " the fileset and continue\n" 444 " -v <format>, --format=<format>\n" 445 " Sets log print format verb and adverbs, where <format> is:\n" 446 " brief help long process raw tag thread threadtime time\n" 447 " and individually flagged modifying adverbs can be added:\n" 448 " color descriptive epoch monotonic printable uid\n" 449 " usec UTC year zone\n" 450 " Multiple -v parameters or comma separated list of format and\n" 451 " format modifiers are allowed.\n" 452 // private and undocumented nsec, no signal, too much noise 453 // useful for -T or -t <timestamp> accurate testing though. 454 " -D, --dividers Print dividers between each log buffer\n" 455 " -c, --clear Clear (flush) the entire log and exit\n" 456 " if Log to File specified, clear fileset instead\n" 457 " -d Dump the log and then exit (don't block)\n" 458 " -e <expr>, --regex=<expr>\n" 459 " Only print lines where the log message matches <expr>\n" 460 " where <expr> is a regular expression\n" 461 // Leave --head undocumented as alias for -m 462 " -m <count>, --max-count=<count>\n" 463 " Quit after printing <count> lines. This is meant to be\n" 464 " paired with --regex, but will work on its own.\n" 465 " --print Paired with --regex and --max-count to let content bypass\n" 466 " regex filter but still stop at number of matches.\n" 467 // Leave --tail undocumented as alias for -t 468 " -t <count> Print only the most recent <count> lines (implies -d)\n" 469 " -t '<time>' Print most recent lines since specified time (implies -d)\n" 470 " -T <count> Print only the most recent <count> lines (does not imply -d)\n" 471 " -T '<time>' Print most recent lines since specified time (not imply -d)\n" 472 " count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'\n" 473 " 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format\n" 474 " -g, --buffer-size Get the size of the ring buffer.\n" 475 " -G <size>, --buffer-size=<size>\n" 476 " Set size of log ring buffer, may suffix with K or M.\n" 477 " -L, --last Dump logs from prior to last reboot\n" 478 // Leave security (Device Owner only installations) and 479 // kernel (userdebug and eng) buffers undocumented. 480 " -b <buffer>, --buffer=<buffer> Request alternate ring buffer, 'main',\n" 481 " 'system', 'radio', 'events', 'crash', 'default' or 'all'.\n" 482 " Multiple -b parameters or comma separated list of buffers are\n" 483 " allowed. Buffers interleaved. Default -b main,system,crash.\n" 484 " -B, --binary Output the log in binary.\n" 485 " -S, --statistics Output statistics.\n" 486 " -p, --prune Print prune white and ~black list. Service is specified as\n" 487 " UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n" 488 " with ~, otherwise weighed for longevity if unadorned. All\n" 489 " other pruning activity is oldest first. Special case ~!\n" 490 " represents an automatic quicker pruning for the noisiest\n" 491 " UID as determined by the current statistics.\n" 492 " -P '<list> ...', --prune='<list> ...'\n" 493 " Set prune white and ~black list, using same format as\n" 494 " listed above. Must be quoted.\n" 495 " --pid=<pid> Only prints logs from the given pid.\n" 496 // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value for match to 2 hours 497 " --wrap Sleep for 2 hours or when buffer about to wrap whichever\n" 498 " comes first. Improves efficiency of polling by providing\n" 499 " an about-to-wrap wakeup.\n"); 500 501 fprintf(context->error, "\nfilterspecs are a series of \n" 502 " <tag>[:priority]\n\n" 503 "where <tag> is a log component tag (or * for all) and priority is:\n" 504 " V Verbose (default for <tag>)\n" 505 " D Debug (default for '*')\n" 506 " I Info\n" 507 " W Warn\n" 508 " E Error\n" 509 " F Fatal\n" 510 " S Silent (suppress all output)\n" 511 "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n" 512 "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n" 513 "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n" 514 "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n" 515 "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n" 516 "or defaults to \"threadtime\"\n\n"); 517 } 518 519 static void show_format_help(android_logcat_context_internal* context) { 520 if (!context->error) return; 521 fprintf(context->error, 522 "-v <format>, --format=<format> options:\n" 523 " Sets log print format verb and adverbs, where <format> is:\n" 524 " brief long process raw tag thread threadtime time\n" 525 " and individually flagged modifying adverbs can be added:\n" 526 " color descriptive epoch monotonic printable uid usec UTC year zone\n" 527 "\nSingle format verbs:\n" 528 " brief Display priority/tag and PID of the process issuing the message.\n" 529 " long Display all metadata fields, separate messages with blank lines.\n" 530 " process Display PID only.\n" 531 " raw Display the raw log message, with no other metadata fields.\n" 532 " tag Display the priority/tag only.\n" 533 " threadtime Display the date, invocation time, priority, tag, and the PID\n" 534 " and TID of the thread issuing the message. (the default format).\n" 535 " time Display the date, invocation time, priority/tag, and PID of the\n" 536 " process issuing the message.\n" 537 "\nAdverb modifiers can be used in combination:\n" 538 " color Display in highlighted color to match priority. i.e. \x1B[38;5;231mVERBOSE\n" 539 " \x1B[38;5;75mDEBUG \x1B[38;5;40mINFO \x1B[38;5;166mWARNING \x1B[38;5;196mERROR FATAL\x1B[0m\n" 540 " descriptive events logs only, descriptions from event-log-tags database.\n" 541 " epoch Display time as seconds since Jan 1 1970.\n" 542 " monotonic Display time as cpu seconds since last boot.\n" 543 " printable Ensure that any binary logging content is escaped.\n" 544 " uid If permitted, display the UID or Android ID of logged process.\n" 545 " usec Display time down the microsecond precision.\n" 546 " UTC Display time as UTC.\n" 547 " year Add the year to the displayed time.\n" 548 " zone Add the local timezone to the displayed time.\n" 549 " \"<zone>\" Print using this public named timezone (experimental).\n\n" 550 ); 551 } 552 // clang-format on 553 554 static int setLogFormat(android_logcat_context_internal* context, 555 const char* formatString) { 556 AndroidLogPrintFormat format; 557 558 format = android_log_formatFromString(formatString); 559 560 // invalid string? 561 if (format == FORMAT_OFF) return -1; 562 563 return android_log_setPrintFormat(context->logformat, format); 564 } 565 566 static const char multipliers[][2] = { { "" }, { "K" }, { "M" }, { "G" } }; 567 568 static unsigned long value_of_size(unsigned long value) { 569 for (unsigned i = 0; 570 (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024); 571 value /= 1024, ++i) 572 ; 573 return value; 574 } 575 576 static const char* multiplier_of_size(unsigned long value) { 577 unsigned i; 578 for (i = 0; 579 (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024); 580 value /= 1024, ++i) 581 ; 582 return multipliers[i]; 583 } 584 585 // String to unsigned int, returns -1 if it fails 586 static bool getSizeTArg(const char* ptr, size_t* val, size_t min = 0, 587 size_t max = SIZE_MAX) { 588 if (!ptr) return false; 589 590 char* endp; 591 errno = 0; 592 size_t ret = (size_t)strtoll(ptr, &endp, 0); 593 594 if (endp[0] || errno) return false; 595 596 if ((ret > max) || (ret < min)) return false; 597 598 *val = ret; 599 return true; 600 } 601 602 static void logcat_panic(android_logcat_context_internal* context, 603 enum helpType showHelp, const char* fmt, ...) { 604 context->retval = EXIT_FAILURE; 605 if (!context->error) { 606 context->stop = true; 607 return; 608 } 609 610 va_list args; 611 va_start(args, fmt); 612 vfprintf(context->error, fmt, args); 613 va_end(args); 614 615 switch (showHelp) { 616 case HELP_TRUE: 617 show_help(context); 618 break; 619 case HELP_FORMAT: 620 show_format_help(context); 621 break; 622 case HELP_FALSE: 623 default: 624 break; 625 } 626 627 context->stop = true; 628 } 629 630 static char* parseTime(log_time& t, const char* cp) { 631 char* ep = t.strptime(cp, "%m-%d %H:%M:%S.%q"); 632 if (ep) return ep; 633 ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q"); 634 if (ep) return ep; 635 return t.strptime(cp, "%s.%q"); 636 } 637 638 // Find last logged line in <outputFileName>, or <outputFileName>.1 639 static log_time lastLogTime(const char* outputFileName) { 640 log_time retval(log_time::EPOCH); 641 if (!outputFileName) return retval; 642 643 std::string directory; 644 const char* file = strrchr(outputFileName, '/'); 645 if (!file) { 646 directory = "."; 647 file = outputFileName; 648 } else { 649 directory = std::string(outputFileName, file - outputFileName); 650 ++file; 651 } 652 653 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()), 654 closedir); 655 if (!dir.get()) return retval; 656 657 log_time now(android_log_clockid()); 658 659 size_t len = strlen(file); 660 log_time modulo(0, NS_PER_SEC); 661 struct dirent* dp; 662 663 while (!!(dp = readdir(dir.get()))) { 664 if ((dp->d_type != DT_REG) || !!strncmp(dp->d_name, file, len) || 665 (dp->d_name[len] && ((dp->d_name[len] != '.') || 666 (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) { 667 continue; 668 } 669 670 std::string file_name = directory; 671 file_name += "/"; 672 file_name += dp->d_name; 673 std::string file; 674 if (!android::base::ReadFileToString(file_name, &file)) continue; 675 676 bool found = false; 677 for (const auto& line : android::base::Split(file, "\n")) { 678 log_time t(log_time::EPOCH); 679 char* ep = parseTime(t, line.c_str()); 680 if (!ep || (*ep != ' ')) continue; 681 // determine the time precision of the logs (eg: msec or usec) 682 for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) { 683 if (t.tv_nsec % (mod * 10)) { 684 modulo.tv_nsec = mod; 685 break; 686 } 687 } 688 // We filter any times later than current as we may not have the 689 // year stored with each log entry. Also, since it is possible for 690 // entries to be recorded out of order (very rare) we select the 691 // maximum we find just in case. 692 if ((t < now) && (t > retval)) { 693 retval = t; 694 found = true; 695 } 696 } 697 // We count on the basename file to be the definitive end, so stop here. 698 if (!dp->d_name[len] && found) break; 699 } 700 if (retval == log_time::EPOCH) return retval; 701 // tail_time prints matching or higher, round up by the modulo to prevent 702 // a replay of the last entry we have just checked. 703 retval += modulo; 704 return retval; 705 } 706 707 const char* getenv(android_logcat_context_internal* context, const char* name) { 708 if (!context->envp || !name || !*name) return nullptr; 709 710 for (size_t len = strlen(name), i = 0; context->envp[i]; ++i) { 711 if (strncmp(context->envp[i], name, len)) continue; 712 if (context->envp[i][len] == '=') return &context->envp[i][len + 1]; 713 } 714 return nullptr; 715 } 716 717 } // namespace android 718 719 void reportErrorName(const char** current, const char* name, 720 bool blockSecurity) { 721 if (*current) return; 722 if (!blockSecurity || (android_name_to_log_id(name) != LOG_ID_SECURITY)) { 723 *current = name; 724 } 725 } 726 727 static int __logcat(android_logcat_context_internal* context) { 728 using namespace android; 729 int err; 730 bool hasSetLogFormat = false; 731 bool clearLog = false; 732 bool allSelected = false; 733 bool getLogSize = false; 734 bool getPruneList = false; 735 bool printStatistics = false; 736 bool printDividers = false; 737 unsigned long setLogSize = 0; 738 const char* setPruneList = nullptr; 739 const char* setId = nullptr; 740 int mode = ANDROID_LOG_RDONLY; 741 std::string forceFilters; 742 log_device_t* dev; 743 struct logger_list* logger_list; 744 size_t tail_lines = 0; 745 log_time tail_time(log_time::EPOCH); 746 size_t pid = 0; 747 bool got_t = false; 748 749 // object instantiations before goto's can happen 750 log_device_t unexpected("unexpected", false); 751 const char* openDeviceFail = nullptr; 752 const char* clearFail = nullptr; 753 const char* setSizeFail = nullptr; 754 const char* getSizeFail = nullptr; 755 int argc = context->argc; 756 char* const* argv = context->argv; 757 758 context->output = stdout; 759 context->error = stderr; 760 761 for (int i = 0; i < argc; ++i) { 762 // Simulate shell stderr redirect parsing 763 if ((argv[i][0] != '2') || (argv[i][1] != '>')) continue; 764 765 // Append to file not implemented, just open file 766 size_t skip = (argv[i][2] == '>') + 2; 767 if (!strcmp(&argv[i][skip], "/dev/null")) { 768 context->stderr_null = true; 769 } else if (!strcmp(&argv[i][skip], "&1")) { 770 context->stderr_stdout = true; 771 } else { 772 // stderr file redirections are not supported 773 fprintf(context->stderr_stdout ? stdout : stderr, 774 "stderr redirection to file %s unsupported, skipping\n", 775 &argv[i][skip]); 776 } 777 // Only the first one 778 break; 779 } 780 781 const char* filename = nullptr; 782 for (int i = 0; i < argc; ++i) { 783 // Simulate shell stdout redirect parsing 784 if (argv[i][0] != '>') continue; 785 786 // Append to file not implemented, just open file 787 filename = &argv[i][(argv[i][1] == '>') + 1]; 788 // Only the first one 789 break; 790 } 791 792 // Deal with setting up file descriptors and FILE pointers 793 if (context->error_fd >= 0) { // Is an error file descriptor supplied? 794 if (context->error_fd == context->output_fd) { 795 context->stderr_stdout = true; 796 } else if (context->stderr_null) { // redirection told us to close it 797 close(context->error_fd); 798 context->error_fd = -1; 799 } else { // All Ok, convert error to a FILE pointer 800 context->error = fdopen(context->error_fd, "web"); 801 if (!context->error) { 802 context->retval = -errno; 803 fprintf(context->stderr_stdout ? stdout : stderr, 804 "Failed to fdopen(error_fd=%d) %s\n", context->error_fd, 805 strerror(errno)); 806 goto exit; 807 } 808 } 809 } 810 if (context->output_fd >= 0) { // Is an output file descriptor supplied? 811 if (filename) { // redirect to file, close supplied file descriptor. 812 close(context->output_fd); 813 context->output_fd = -1; 814 } else { // All Ok, convert output to a FILE pointer 815 context->output = fdopen(context->output_fd, "web"); 816 if (!context->output) { 817 context->retval = -errno; 818 fprintf(context->stderr_stdout ? stdout : context->error, 819 "Failed to fdopen(output_fd=%d) %s\n", 820 context->output_fd, strerror(errno)); 821 goto exit; 822 } 823 } 824 } 825 if (filename) { // We supplied an output file redirected in command line 826 context->output = fopen(filename, "web"); 827 } 828 // Deal with 2>&1 829 if (context->stderr_stdout) context->error = context->output; 830 // Deal with 2>/dev/null 831 if (context->stderr_null) { 832 context->error_fd = -1; 833 context->error = nullptr; 834 } 835 // Only happens if output=stdout or output=filename 836 if ((context->output_fd < 0) && context->output) { 837 context->output_fd = fileno(context->output); 838 } 839 // Only happens if error=stdout || error=stderr 840 if ((context->error_fd < 0) && context->error) { 841 context->error_fd = fileno(context->error); 842 } 843 844 context->logformat = android_log_format_new(); 845 846 if (argc == 2 && !strcmp(argv[1], "--help")) { 847 show_help(context); 848 context->retval = EXIT_SUCCESS; 849 goto exit; 850 } 851 852 // meant to catch comma-delimited values, but cast a wider 853 // net for stability dealing with possible mistaken inputs. 854 static const char delimiters[] = ",:; \t\n\r\f"; 855 856 struct getopt_context optctx; 857 INIT_GETOPT_CONTEXT(optctx); 858 optctx.opterr = !!context->error; 859 optctx.optstderr = context->error; 860 861 for (;;) { 862 int ret; 863 864 int option_index = 0; 865 // list of long-argument only strings for later comparison 866 static const char pid_str[] = "pid"; 867 static const char debug_str[] = "debug"; 868 static const char id_str[] = "id"; 869 static const char wrap_str[] = "wrap"; 870 static const char print_str[] = "print"; 871 // clang-format off 872 static const struct option long_options[] = { 873 { "binary", no_argument, nullptr, 'B' }, 874 { "buffer", required_argument, nullptr, 'b' }, 875 { "buffer-size", optional_argument, nullptr, 'g' }, 876 { "clear", no_argument, nullptr, 'c' }, 877 { debug_str, no_argument, nullptr, 0 }, 878 { "dividers", no_argument, nullptr, 'D' }, 879 { "file", required_argument, nullptr, 'f' }, 880 { "format", required_argument, nullptr, 'v' }, 881 // hidden and undocumented reserved alias for --regex 882 { "grep", required_argument, nullptr, 'e' }, 883 // hidden and undocumented reserved alias for --max-count 884 { "head", required_argument, nullptr, 'm' }, 885 { "help", no_argument, nullptr, 'h' }, 886 { id_str, required_argument, nullptr, 0 }, 887 { "last", no_argument, nullptr, 'L' }, 888 { "max-count", required_argument, nullptr, 'm' }, 889 { pid_str, required_argument, nullptr, 0 }, 890 { print_str, no_argument, nullptr, 0 }, 891 { "prune", optional_argument, nullptr, 'p' }, 892 { "regex", required_argument, nullptr, 'e' }, 893 { "rotate-count", required_argument, nullptr, 'n' }, 894 { "rotate-kbytes", required_argument, nullptr, 'r' }, 895 { "statistics", no_argument, nullptr, 'S' }, 896 // hidden and undocumented reserved alias for -t 897 { "tail", required_argument, nullptr, 't' }, 898 // support, but ignore and do not document, the optional argument 899 { wrap_str, optional_argument, nullptr, 0 }, 900 { nullptr, 0, nullptr, 0 } 901 }; 902 // clang-format on 903 904 ret = getopt_long_r(argc, argv, ":cdDhLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", 905 long_options, &option_index, &optctx); 906 if (ret < 0) break; 907 908 switch (ret) { 909 case 0: 910 // only long options 911 if (long_options[option_index].name == pid_str) { 912 // ToDo: determine runtime PID_MAX? 913 if (!getSizeTArg(optctx.optarg, &pid, 1)) { 914 logcat_panic(context, HELP_TRUE, "%s %s out of range\n", 915 long_options[option_index].name, 916 optctx.optarg); 917 goto exit; 918 } 919 break; 920 } 921 if (long_options[option_index].name == wrap_str) { 922 mode |= ANDROID_LOG_WRAP | ANDROID_LOG_RDONLY | 923 ANDROID_LOG_NONBLOCK; 924 // ToDo: implement API that supports setting a wrap timeout 925 size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT; 926 if (optctx.optarg && 927 !getSizeTArg(optctx.optarg, &dummy, 1)) { 928 logcat_panic(context, HELP_TRUE, "%s %s out of range\n", 929 long_options[option_index].name, 930 optctx.optarg); 931 goto exit; 932 } 933 if ((dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) && 934 context->error) { 935 fprintf(context->error, 936 "WARNING: %s %u seconds, ignoring %zu\n", 937 long_options[option_index].name, 938 ANDROID_LOG_WRAP_DEFAULT_TIMEOUT, dummy); 939 } 940 break; 941 } 942 if (long_options[option_index].name == print_str) { 943 context->printItAnyways = true; 944 break; 945 } 946 if (long_options[option_index].name == debug_str) { 947 context->debug = true; 948 break; 949 } 950 if (long_options[option_index].name == id_str) { 951 setId = (optctx.optarg && optctx.optarg[0]) ? optctx.optarg 952 : nullptr; 953 } 954 break; 955 956 case 's': 957 // default to all silent 958 android_log_addFilterRule(context->logformat, "*:s"); 959 break; 960 961 case 'c': 962 clearLog = true; 963 mode |= ANDROID_LOG_WRONLY; 964 break; 965 966 case 'L': 967 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | 968 ANDROID_LOG_NONBLOCK; 969 break; 970 971 case 'd': 972 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK; 973 break; 974 975 case 't': 976 got_t = true; 977 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK; 978 // FALLTHRU 979 case 'T': 980 if (strspn(optctx.optarg, "0123456789") != 981 strlen(optctx.optarg)) { 982 char* cp = parseTime(tail_time, optctx.optarg); 983 if (!cp) { 984 logcat_panic(context, HELP_FALSE, 985 "-%c \"%s\" not in time format\n", ret, 986 optctx.optarg); 987 goto exit; 988 } 989 if (*cp) { 990 char c = *cp; 991 *cp = '\0'; 992 if (context->error) { 993 fprintf( 994 context->error, 995 "WARNING: -%c \"%s\"\"%c%s\" time truncated\n", 996 ret, optctx.optarg, c, cp + 1); 997 } 998 *cp = c; 999 } 1000 } else { 1001 if (!getSizeTArg(optctx.optarg, &tail_lines, 1)) { 1002 if (context->error) { 1003 fprintf(context->error, 1004 "WARNING: -%c %s invalid, setting to 1\n", 1005 ret, optctx.optarg); 1006 } 1007 tail_lines = 1; 1008 } 1009 } 1010 break; 1011 1012 case 'D': 1013 printDividers = true; 1014 break; 1015 1016 case 'e': 1017 context->regex = new pcrecpp::RE(optctx.optarg); 1018 break; 1019 1020 case 'm': { 1021 char* end = nullptr; 1022 if (!getSizeTArg(optctx.optarg, &context->maxCount)) { 1023 logcat_panic(context, HELP_FALSE, 1024 "-%c \"%s\" isn't an " 1025 "integer greater than zero\n", 1026 ret, optctx.optarg); 1027 goto exit; 1028 } 1029 } break; 1030 1031 case 'g': 1032 if (!optctx.optarg) { 1033 getLogSize = true; 1034 break; 1035 } 1036 // FALLTHRU 1037 1038 case 'G': { 1039 char* cp; 1040 if (strtoll(optctx.optarg, &cp, 0) > 0) { 1041 setLogSize = strtoll(optctx.optarg, &cp, 0); 1042 } else { 1043 setLogSize = 0; 1044 } 1045 1046 switch (*cp) { 1047 case 'g': 1048 case 'G': 1049 setLogSize *= 1024; 1050 // FALLTHRU 1051 case 'm': 1052 case 'M': 1053 setLogSize *= 1024; 1054 // FALLTHRU 1055 case 'k': 1056 case 'K': 1057 setLogSize *= 1024; 1058 // FALLTHRU 1059 case '\0': 1060 break; 1061 1062 default: 1063 setLogSize = 0; 1064 } 1065 1066 if (!setLogSize) { 1067 logcat_panic(context, HELP_FALSE, 1068 "ERROR: -G <num><multiplier>\n"); 1069 goto exit; 1070 } 1071 } break; 1072 1073 case 'p': 1074 if (!optctx.optarg) { 1075 getPruneList = true; 1076 break; 1077 } 1078 // FALLTHRU 1079 1080 case 'P': 1081 setPruneList = optctx.optarg; 1082 break; 1083 1084 case 'b': { 1085 std::unique_ptr<char, void (*)(void*)> buffers( 1086 strdup(optctx.optarg), free); 1087 char* arg = buffers.get(); 1088 unsigned idMask = 0; 1089 char* sv = nullptr; // protect against -ENOMEM above 1090 while (!!(arg = strtok_r(arg, delimiters, &sv))) { 1091 if (!strcmp(arg, "default")) { 1092 idMask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | 1093 (1 << LOG_ID_CRASH); 1094 } else if (!strcmp(arg, "all")) { 1095 allSelected = true; 1096 idMask = (unsigned)-1; 1097 } else { 1098 log_id_t log_id = android_name_to_log_id(arg); 1099 const char* name = android_log_id_to_name(log_id); 1100 1101 if (!!strcmp(name, arg)) { 1102 logcat_panic(context, HELP_TRUE, 1103 "unknown buffer %s\n", arg); 1104 goto exit; 1105 } 1106 if (log_id == LOG_ID_SECURITY) allSelected = false; 1107 idMask |= (1 << log_id); 1108 } 1109 arg = nullptr; 1110 } 1111 1112 for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) { 1113 const char* name = android_log_id_to_name((log_id_t)i); 1114 log_id_t log_id = android_name_to_log_id(name); 1115 1116 if (log_id != (log_id_t)i) continue; 1117 if (!(idMask & (1 << i))) continue; 1118 1119 bool found = false; 1120 for (dev = context->devices; dev; dev = dev->next) { 1121 if (!strcmp(name, dev->device)) { 1122 found = true; 1123 break; 1124 } 1125 if (!dev->next) break; 1126 } 1127 if (found) continue; 1128 1129 bool binary = 1130 !strcmp(name, "events") || !strcmp(name, "security"); 1131 log_device_t* d = new log_device_t(name, binary); 1132 1133 if (dev) { 1134 dev->next = d; 1135 dev = d; 1136 } else { 1137 context->devices = dev = d; 1138 } 1139 context->devCount++; 1140 } 1141 } break; 1142 1143 case 'B': 1144 context->printBinary = 1; 1145 break; 1146 1147 case 'f': 1148 if ((tail_time == log_time::EPOCH) && !tail_lines) { 1149 tail_time = lastLogTime(optctx.optarg); 1150 } 1151 // redirect output to a file 1152 context->outputFileName = optctx.optarg; 1153 break; 1154 1155 case 'r': 1156 if (!getSizeTArg(optctx.optarg, &context->logRotateSizeKBytes, 1157 1)) { 1158 logcat_panic(context, HELP_TRUE, 1159 "Invalid parameter \"%s\" to -r\n", 1160 optctx.optarg); 1161 goto exit; 1162 } 1163 break; 1164 1165 case 'n': 1166 if (!getSizeTArg(optctx.optarg, &context->maxRotatedLogs, 1)) { 1167 logcat_panic(context, HELP_TRUE, 1168 "Invalid parameter \"%s\" to -n\n", 1169 optctx.optarg); 1170 goto exit; 1171 } 1172 break; 1173 1174 case 'v': { 1175 if (!strcmp(optctx.optarg, "help") || 1176 !strcmp(optctx.optarg, "--help")) { 1177 show_format_help(context); 1178 context->retval = EXIT_SUCCESS; 1179 goto exit; 1180 } 1181 std::unique_ptr<char, void (*)(void*)> formats( 1182 strdup(optctx.optarg), free); 1183 char* arg = formats.get(); 1184 unsigned idMask = 0; 1185 char* sv = nullptr; // protect against -ENOMEM above 1186 while (!!(arg = strtok_r(arg, delimiters, &sv))) { 1187 err = setLogFormat(context, arg); 1188 if (err < 0) { 1189 logcat_panic(context, HELP_FORMAT, 1190 "Invalid parameter \"%s\" to -v\n", arg); 1191 goto exit; 1192 } 1193 arg = nullptr; 1194 if (err) hasSetLogFormat = true; 1195 } 1196 } break; 1197 1198 case 'Q': 1199 #define LOGCAT_FILTER "androidboot.logcat=" 1200 #define CONSOLE_PIPE_OPTION "androidboot.consolepipe=" 1201 #define CONSOLE_OPTION "androidboot.console=" 1202 #define QEMU_PROPERTY "ro.kernel.qemu" 1203 #define QEMU_CMDLINE "qemu.cmdline" 1204 // This is a *hidden* option used to start a version of logcat 1205 // in an emulated device only. It basically looks for 1206 // androidboot.logcat= on the kernel command line. If 1207 // something is found, it extracts a log filter and uses it to 1208 // run the program. The logcat output will go to consolepipe if 1209 // androiboot.consolepipe (e.g. qemu_pipe) is given, otherwise, 1210 // it goes to androidboot.console (e.g. tty) 1211 { 1212 // if not in emulator, exit quietly 1213 if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) { 1214 context->retval = EXIT_SUCCESS; 1215 goto exit; 1216 } 1217 1218 std::string cmdline = android::base::GetProperty(QEMU_CMDLINE, ""); 1219 if (cmdline.empty()) { 1220 android::base::ReadFileToString("/proc/cmdline", &cmdline); 1221 } 1222 1223 const char* logcatFilter = strstr(cmdline.c_str(), LOGCAT_FILTER); 1224 // if nothing found or invalid filters, exit quietly 1225 if (!logcatFilter) { 1226 context->retval = EXIT_SUCCESS; 1227 goto exit; 1228 } 1229 1230 const char* p = logcatFilter + strlen(LOGCAT_FILTER); 1231 const char* q = strpbrk(p, " \t\n\r"); 1232 if (!q) q = p + strlen(p); 1233 forceFilters = std::string(p, q); 1234 1235 // redirect our output to the emulator console pipe or console 1236 const char* consolePipe = 1237 strstr(cmdline.c_str(), CONSOLE_PIPE_OPTION); 1238 const char* console = 1239 strstr(cmdline.c_str(), CONSOLE_OPTION); 1240 1241 if (consolePipe) { 1242 p = consolePipe + strlen(CONSOLE_PIPE_OPTION); 1243 } else if (console) { 1244 p = console + strlen(CONSOLE_OPTION); 1245 } else { 1246 context->retval = EXIT_FAILURE; 1247 goto exit; 1248 } 1249 1250 q = strpbrk(p, " \t\n\r"); 1251 int len = q ? q - p : strlen(p); 1252 std::string devname = "/dev/" + std::string(p, len); 1253 std::string pipePurpose("pipe:logcat"); 1254 if (consolePipe) { 1255 // example: "qemu_pipe,pipe:logcat" 1256 // upon opening of /dev/qemu_pipe, the "pipe:logcat" 1257 // string with trailing '\0' should be written to the fd 1258 size_t pos = devname.find(","); 1259 if (pos != std::string::npos) { 1260 pipePurpose = devname.substr(pos + 1); 1261 devname = devname.substr(0, pos); 1262 } 1263 } 1264 cmdline.erase(); 1265 1266 if (context->error) { 1267 fprintf(context->error, "logcat using %s\n", 1268 devname.c_str()); 1269 } 1270 1271 FILE* fp = fopen(devname.c_str(), "web"); 1272 devname.erase(); 1273 if (!fp) break; 1274 1275 if (consolePipe) { 1276 // need the trailing '\0' 1277 if(!android::base::WriteFully(fileno(fp), pipePurpose.c_str(), 1278 pipePurpose.size() + 1)) { 1279 fclose(fp); 1280 context->retval = EXIT_FAILURE; 1281 goto exit; 1282 } 1283 } 1284 1285 // close output and error channels, replace with console 1286 android::close_output(context); 1287 android::close_error(context); 1288 context->stderr_stdout = true; 1289 context->output = fp; 1290 context->output_fd = fileno(fp); 1291 if (context->stderr_null) break; 1292 context->stderr_stdout = true; 1293 context->error = fp; 1294 context->error_fd = fileno(fp); 1295 } 1296 break; 1297 1298 case 'S': 1299 printStatistics = true; 1300 break; 1301 1302 case ':': 1303 logcat_panic(context, HELP_TRUE, 1304 "Option -%c needs an argument\n", optctx.optopt); 1305 goto exit; 1306 1307 case 'h': 1308 show_help(context); 1309 show_format_help(context); 1310 goto exit; 1311 1312 default: 1313 logcat_panic(context, HELP_TRUE, "Unrecognized Option %c\n", 1314 optctx.optopt); 1315 goto exit; 1316 } 1317 } 1318 1319 if (context->maxCount && got_t) { 1320 logcat_panic(context, HELP_TRUE, 1321 "Cannot use -m (--max-count) and -t together\n"); 1322 goto exit; 1323 } 1324 if (context->printItAnyways && (!context->regex || !context->maxCount)) { 1325 // One day it would be nice if --print -v color and --regex <expr> 1326 // could play with each other and show regex highlighted content. 1327 // clang-format off 1328 if (context->error) { 1329 fprintf(context->error, "WARNING: " 1330 "--print ignored, to be used in combination with\n" 1331 " " 1332 "--regex <expr> and --max-count <N>\n"); 1333 } 1334 context->printItAnyways = false; 1335 } 1336 1337 if (!context->devices) { 1338 dev = context->devices = new log_device_t("main", false); 1339 context->devCount = 1; 1340 if (android_name_to_log_id("system") == LOG_ID_SYSTEM) { 1341 dev = dev->next = new log_device_t("system", false); 1342 context->devCount++; 1343 } 1344 if (android_name_to_log_id("crash") == LOG_ID_CRASH) { 1345 dev = dev->next = new log_device_t("crash", false); 1346 context->devCount++; 1347 } 1348 } 1349 1350 if (!!context->logRotateSizeKBytes && !context->outputFileName) { 1351 logcat_panic(context, HELP_TRUE, "-r requires -f as well\n"); 1352 goto exit; 1353 } 1354 1355 if (!!setId) { 1356 if (!context->outputFileName) { 1357 logcat_panic(context, HELP_TRUE, 1358 "--id='%s' requires -f as well\n", setId); 1359 goto exit; 1360 } 1361 1362 std::string file_name = android::base::StringPrintf( 1363 "%s.id", context->outputFileName); 1364 std::string file; 1365 bool file_ok = android::base::ReadFileToString(file_name, &file); 1366 android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR, 1367 getuid(), getgid()); 1368 if (!file_ok || !file.compare(setId)) setId = nullptr; 1369 } 1370 1371 if (!hasSetLogFormat) { 1372 const char* logFormat = android::getenv(context, "ANDROID_PRINTF_LOG"); 1373 1374 if (!!logFormat) { 1375 std::unique_ptr<char, void (*)(void*)> formats(strdup(logFormat), 1376 free); 1377 char* sv = nullptr; // protect against -ENOMEM above 1378 char* arg = formats.get(); 1379 while (!!(arg = strtok_r(arg, delimiters, &sv))) { 1380 err = setLogFormat(context, arg); 1381 // environment should not cause crash of logcat 1382 if ((err < 0) && context->error) { 1383 fprintf(context->error, 1384 "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg); 1385 } 1386 arg = nullptr; 1387 if (err > 0) hasSetLogFormat = true; 1388 } 1389 } 1390 if (!hasSetLogFormat) { 1391 setLogFormat(context, "threadtime"); 1392 } 1393 } 1394 1395 if (forceFilters.size()) { 1396 err = android_log_addFilterString(context->logformat, 1397 forceFilters.c_str()); 1398 if (err < 0) { 1399 logcat_panic(context, HELP_FALSE, 1400 "Invalid filter expression in logcat args\n"); 1401 goto exit; 1402 } 1403 } else if (argc == optctx.optind) { 1404 // Add from environment variable 1405 const char* env_tags_orig = android::getenv(context, "ANDROID_LOG_TAGS"); 1406 1407 if (!!env_tags_orig) { 1408 err = android_log_addFilterString(context->logformat, 1409 env_tags_orig); 1410 1411 if (err < 0) { 1412 logcat_panic(context, HELP_TRUE, 1413 "Invalid filter expression in ANDROID_LOG_TAGS\n"); 1414 goto exit; 1415 } 1416 } 1417 } else { 1418 // Add from commandline 1419 for (int i = optctx.optind ; i < argc ; i++) { 1420 // skip stderr redirections of _all_ kinds 1421 if ((argv[i][0] == '2') && (argv[i][1] == '>')) continue; 1422 // skip stdout redirections of _all_ kinds 1423 if (argv[i][0] == '>') continue; 1424 1425 err = android_log_addFilterString(context->logformat, argv[i]); 1426 if (err < 0) { 1427 logcat_panic(context, HELP_TRUE, 1428 "Invalid filter expression '%s'\n", argv[i]); 1429 goto exit; 1430 } 1431 } 1432 } 1433 1434 dev = context->devices; 1435 if (tail_time != log_time::EPOCH) { 1436 logger_list = android_logger_list_alloc_time(mode, tail_time, pid); 1437 } else { 1438 logger_list = android_logger_list_alloc(mode, tail_lines, pid); 1439 } 1440 // We have three orthogonal actions below to clear, set log size and 1441 // get log size. All sharing the same iteration loop. 1442 while (dev) { 1443 dev->logger_list = logger_list; 1444 dev->logger = android_logger_open(logger_list, 1445 android_name_to_log_id(dev->device)); 1446 if (!dev->logger) { 1447 reportErrorName(&openDeviceFail, dev->device, allSelected); 1448 dev = dev->next; 1449 continue; 1450 } 1451 1452 if (clearLog || setId) { 1453 if (context->outputFileName) { 1454 int maxRotationCountDigits = 1455 (context->maxRotatedLogs > 0) ? 1456 (int)(floor(log10(context->maxRotatedLogs) + 1)) : 1457 0; 1458 1459 for (int i = context->maxRotatedLogs ; i >= 0 ; --i) { 1460 std::string file; 1461 1462 if (!i) { 1463 file = android::base::StringPrintf( 1464 "%s", context->outputFileName); 1465 } else { 1466 file = android::base::StringPrintf("%s.%.*d", 1467 context->outputFileName, maxRotationCountDigits, i); 1468 } 1469 1470 if (!file.length()) { 1471 perror("while clearing log files"); 1472 reportErrorName(&clearFail, dev->device, allSelected); 1473 break; 1474 } 1475 1476 err = unlink(file.c_str()); 1477 1478 if (err < 0 && errno != ENOENT && !clearFail) { 1479 perror("while clearing log files"); 1480 reportErrorName(&clearFail, dev->device, allSelected); 1481 } 1482 } 1483 } else if (android_logger_clear(dev->logger)) { 1484 reportErrorName(&clearFail, dev->device, allSelected); 1485 } 1486 } 1487 1488 if (setLogSize) { 1489 if (android_logger_set_log_size(dev->logger, setLogSize)) { 1490 reportErrorName(&setSizeFail, dev->device, allSelected); 1491 } 1492 } 1493 1494 if (getLogSize) { 1495 long size = android_logger_get_log_size(dev->logger); 1496 long readable = android_logger_get_log_readable_size(dev->logger); 1497 1498 if ((size < 0) || (readable < 0)) { 1499 reportErrorName(&getSizeFail, dev->device, allSelected); 1500 } else { 1501 std::string str = android::base::StringPrintf( 1502 "%s: ring buffer is %ld%sb (%ld%sb consumed)," 1503 " max entry is %db, max payload is %db\n", 1504 dev->device, 1505 value_of_size(size), multiplier_of_size(size), 1506 value_of_size(readable), multiplier_of_size(readable), 1507 (int)LOGGER_ENTRY_MAX_LEN, 1508 (int)LOGGER_ENTRY_MAX_PAYLOAD); 1509 TEMP_FAILURE_RETRY(write(context->output_fd, 1510 str.data(), str.length())); 1511 } 1512 } 1513 1514 dev = dev->next; 1515 } 1516 1517 context->retval = EXIT_SUCCESS; 1518 1519 // report any errors in the above loop and exit 1520 if (openDeviceFail) { 1521 logcat_panic(context, HELP_FALSE, 1522 "Unable to open log device '%s'\n", openDeviceFail); 1523 goto close; 1524 } 1525 if (clearFail) { 1526 logcat_panic(context, HELP_FALSE, 1527 "failed to clear the '%s' log\n", clearFail); 1528 goto close; 1529 } 1530 if (setSizeFail) { 1531 logcat_panic(context, HELP_FALSE, 1532 "failed to set the '%s' log size\n", setSizeFail); 1533 goto close; 1534 } 1535 if (getSizeFail) { 1536 logcat_panic(context, HELP_FALSE, 1537 "failed to get the readable '%s' log size", getSizeFail); 1538 goto close; 1539 } 1540 1541 if (setPruneList) { 1542 size_t len = strlen(setPruneList); 1543 // extra 32 bytes are needed by android_logger_set_prune_list 1544 size_t bLen = len + 32; 1545 char* buf = nullptr; 1546 if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) { 1547 buf[len] = '\0'; 1548 if (android_logger_set_prune_list(logger_list, buf, bLen)) { 1549 logcat_panic(context, HELP_FALSE, 1550 "failed to set the prune list"); 1551 } 1552 free(buf); 1553 } else { 1554 logcat_panic(context, HELP_FALSE, 1555 "failed to set the prune list (alloc)"); 1556 } 1557 goto close; 1558 } 1559 1560 if (printStatistics || getPruneList) { 1561 size_t len = 8192; 1562 char* buf; 1563 1564 for (int retry = 32; (retry >= 0) && ((buf = new char[len])); 1565 delete[] buf, buf = nullptr, --retry) { 1566 if (getPruneList) { 1567 android_logger_get_prune_list(logger_list, buf, len); 1568 } else { 1569 android_logger_get_statistics(logger_list, buf, len); 1570 } 1571 buf[len - 1] = '\0'; 1572 if (atol(buf) < 3) { 1573 delete[] buf; 1574 buf = nullptr; 1575 break; 1576 } 1577 size_t ret = atol(buf) + 1; 1578 if (ret <= len) { 1579 len = ret; 1580 break; 1581 } 1582 len = ret; 1583 } 1584 1585 if (!buf) { 1586 logcat_panic(context, HELP_FALSE, "failed to read data"); 1587 goto close; 1588 } 1589 1590 // remove trailing FF 1591 char* cp = buf + len - 1; 1592 *cp = '\0'; 1593 bool truncated = *--cp != '\f'; 1594 if (!truncated) *cp = '\0'; 1595 1596 // squash out the byte count 1597 cp = buf; 1598 if (!truncated) { 1599 while (isdigit(*cp)) ++cp; 1600 if (*cp == '\n') ++cp; 1601 } 1602 1603 len = strlen(cp); 1604 TEMP_FAILURE_RETRY(write(context->output_fd, cp, len)); 1605 delete[] buf; 1606 goto close; 1607 } 1608 1609 if (getLogSize || setLogSize || clearLog) goto close; 1610 1611 setupOutputAndSchedulingPolicy(context, !(mode & ANDROID_LOG_NONBLOCK)); 1612 if (context->stop) goto close; 1613 1614 // LOG_EVENT_INT(10, 12345); 1615 // LOG_EVENT_LONG(11, 0x1122334455667788LL); 1616 // LOG_EVENT_STRING(0, "whassup, doc?"); 1617 1618 dev = nullptr; 1619 1620 while (!context->stop && 1621 (!context->maxCount || (context->printCount < context->maxCount))) { 1622 struct log_msg log_msg; 1623 int ret = android_logger_list_read(logger_list, &log_msg); 1624 if (!ret) { 1625 logcat_panic(context, HELP_FALSE, "read: unexpected EOF!\n"); 1626 break; 1627 } 1628 1629 if (ret < 0) { 1630 if (ret == -EAGAIN) break; 1631 1632 if (ret == -EIO) { 1633 logcat_panic(context, HELP_FALSE, "read: unexpected EOF!\n"); 1634 break; 1635 } 1636 if (ret == -EINVAL) { 1637 logcat_panic(context, HELP_FALSE, "read: unexpected length.\n"); 1638 break; 1639 } 1640 logcat_panic(context, HELP_FALSE, "logcat read failure"); 1641 break; 1642 } 1643 1644 log_device_t* d; 1645 for (d = context->devices; d; d = d->next) { 1646 if (android_name_to_log_id(d->device) == log_msg.id()) break; 1647 } 1648 if (!d) { 1649 context->devCount = 2; // set to Multiple 1650 d = &unexpected; 1651 d->binary = log_msg.id() == LOG_ID_EVENTS; 1652 } 1653 1654 if (dev != d) { 1655 dev = d; 1656 maybePrintStart(context, dev, printDividers); 1657 if (context->stop) break; 1658 } 1659 if (context->printBinary) { 1660 printBinary(context, &log_msg); 1661 } else { 1662 processBuffer(context, dev, &log_msg); 1663 } 1664 } 1665 1666 close: 1667 // Short and sweet. Implemented generic version in android_logcat_destroy. 1668 while (!!(dev = context->devices)) { 1669 context->devices = dev->next; 1670 delete dev; 1671 } 1672 android_logger_list_free(logger_list); 1673 1674 exit: 1675 // close write end of pipe to help things along 1676 if (context->output_fd == context->fds[1]) { 1677 android::close_output(context); 1678 } 1679 if (context->error_fd == context->fds[1]) { 1680 android::close_error(context); 1681 } 1682 if (context->fds[1] >= 0) { 1683 // NB: should be closed by the above 1684 int save_errno = errno; 1685 close(context->fds[1]); 1686 errno = save_errno; 1687 context->fds[1] = -1; 1688 } 1689 context->thread_stopped = true; 1690 return context->retval; 1691 } 1692 1693 // Can block 1694 int android_logcat_run_command(android_logcat_context ctx, 1695 int output, int error, 1696 int argc, char* const* argv, 1697 char* const* envp) { 1698 android_logcat_context_internal* context = ctx; 1699 1700 context->output_fd = output; 1701 context->error_fd = error; 1702 context->argc = argc; 1703 context->argv = argv; 1704 context->envp = envp; 1705 context->stop = false; 1706 context->thread_stopped = false; 1707 return __logcat(context); 1708 } 1709 1710 // starts a thread, opens a pipe, returns reading end. 1711 int android_logcat_run_command_thread(android_logcat_context ctx, 1712 int argc, char* const* argv, 1713 char* const* envp) { 1714 android_logcat_context_internal* context = ctx; 1715 1716 int save_errno = EBUSY; 1717 if ((context->fds[0] >= 0) || (context->fds[1] >= 0)) goto exit; 1718 1719 if (pipe(context->fds) < 0) { 1720 save_errno = errno; 1721 goto exit; 1722 } 1723 1724 pthread_attr_t attr; 1725 if (pthread_attr_init(&attr)) { 1726 save_errno = errno; 1727 goto close_exit; 1728 } 1729 1730 struct sched_param param; 1731 memset(¶m, 0, sizeof(param)); 1732 pthread_attr_setschedparam(&attr, ¶m); 1733 pthread_attr_setschedpolicy(&attr, SCHED_BATCH); 1734 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) { 1735 int save_errno = errno; 1736 goto pthread_attr_exit; 1737 } 1738 1739 context->stop = false; 1740 context->thread_stopped = false; 1741 context->output_fd = context->fds[1]; 1742 // save off arguments so they remain while thread is active. 1743 for (int i = 0; i < argc; ++i) { 1744 context->args.push_back(std::string(argv[i])); 1745 } 1746 // save off environment so they remain while thread is active. 1747 if (envp) for (size_t i = 0; envp[i]; ++i) { 1748 context->envs.push_back(std::string(envp[i])); 1749 } 1750 1751 for (auto& str : context->args) { 1752 context->argv_hold.push_back(str.c_str()); 1753 } 1754 context->argv_hold.push_back(nullptr); 1755 for (auto& str : context->envs) { 1756 context->envp_hold.push_back(str.c_str()); 1757 } 1758 context->envp_hold.push_back(nullptr); 1759 1760 context->argc = context->argv_hold.size() - 1; 1761 context->argv = (char* const*)&context->argv_hold[0]; 1762 context->envp = (char* const*)&context->envp_hold[0]; 1763 1764 #ifdef DEBUG 1765 fprintf(stderr, "argv[%d] = {", context->argc); 1766 for (auto str : context->argv_hold) { 1767 fprintf(stderr, " \"%s\"", str ?: "nullptr"); 1768 } 1769 fprintf(stderr, " }\n"); 1770 fflush(stderr); 1771 #endif 1772 context->retval = EXIT_SUCCESS; 1773 if (pthread_create(&context->thr, &attr, 1774 (void*(*)(void*))__logcat, context)) { 1775 int save_errno = errno; 1776 goto argv_exit; 1777 } 1778 pthread_attr_destroy(&attr); 1779 1780 return context->fds[0]; 1781 1782 argv_exit: 1783 context->argv_hold.clear(); 1784 context->args.clear(); 1785 context->envp_hold.clear(); 1786 context->envs.clear(); 1787 pthread_attr_exit: 1788 pthread_attr_destroy(&attr); 1789 close_exit: 1790 close(context->fds[0]); 1791 context->fds[0] = -1; 1792 close(context->fds[1]); 1793 context->fds[1] = -1; 1794 exit: 1795 errno = save_errno; 1796 context->stop = true; 1797 context->thread_stopped = true; 1798 context->retval = EXIT_FAILURE; 1799 return -1; 1800 } 1801 1802 // test if the thread is still doing 'stuff' 1803 int android_logcat_run_command_thread_running(android_logcat_context ctx) { 1804 android_logcat_context_internal* context = ctx; 1805 1806 return context->thread_stopped == false; 1807 } 1808 1809 // Finished with context 1810 int android_logcat_destroy(android_logcat_context* ctx) { 1811 android_logcat_context_internal* context = *ctx; 1812 1813 if (!context) return -EBADF; 1814 1815 *ctx = nullptr; 1816 1817 context->stop = true; 1818 1819 while (context->thread_stopped == false) { 1820 // Makes me sad, replace thread_stopped with semaphore. Short lived. 1821 sched_yield(); 1822 } 1823 1824 delete context->regex; 1825 context->argv_hold.clear(); 1826 context->args.clear(); 1827 context->envp_hold.clear(); 1828 context->envs.clear(); 1829 if (context->fds[0] >= 0) { 1830 close(context->fds[0]); 1831 context->fds[0] = -1; 1832 } 1833 android::close_output(context); 1834 android::close_error(context); 1835 if (context->fds[1] >= 0) { 1836 // NB: could be closed by the above fclose(s), ignore error. 1837 int save_errno = errno; 1838 close(context->fds[1]); 1839 errno = save_errno; 1840 context->fds[1] = -1; 1841 } 1842 1843 android_closeEventTagMap(context->eventTagMap); 1844 1845 // generic cleanup of devices list to handle all possible dirty cases 1846 log_device_t* dev; 1847 while (!!(dev = context->devices)) { 1848 struct logger_list* logger_list = dev->logger_list; 1849 if (logger_list) { 1850 for (log_device_t* d = dev; d; d = d->next) { 1851 if (d->logger_list == logger_list) d->logger_list = nullptr; 1852 } 1853 android_logger_list_free(logger_list); 1854 } 1855 context->devices = dev->next; 1856 delete dev; 1857 } 1858 1859 int retval = context->retval; 1860 1861 free(context); 1862 1863 return retval; 1864 } 1865