1 /*
2 * Copyright (C) 2006 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 <ctype.h>
18 #include <dirent.h>
19 #include <errno.h>
20 #include <error.h>
21 #include <fcntl.h>
22 #include <getopt.h>
23 #include <linux/f2fs.h>
24 #include <math.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/ioctl.h>
32 #include <sys/resource.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <time.h>
36 #include <unistd.h>
37
38 #include <memory>
39 #include <regex>
40 #include <set>
41 #include <string>
42 #include <utility>
43 #include <vector>
44
45 #include <android-base/file.h>
46 #include <android-base/macros.h>
47 #include <android-base/parseint.h>
48 #include <android-base/properties.h>
49 #include <android-base/stringprintf.h>
50 #include <android-base/strings.h>
51 #include <android-base/unique_fd.h>
52 #include <android/log.h>
53 #include <log/event_tag_map.h>
54 #include <log/log_id.h>
55 #include <log/log_read.h>
56 #include <log/logprint.h>
57 #include <private/android_logger.h>
58 #include <processgroup/sched_policy.h>
59 #include <system/thread_defs.h>
60
61 #define DEFAULT_MAX_ROTATED_LOGS 4
62
63 using android::base::Join;
64 using android::base::ParseByteCount;
65 using android::base::ParseUint;
66 using android::base::Split;
67 using android::base::StringPrintf;
68 using android::base::WaitForProperty;
69 using android::base::WriteFully;
70
71 class Logcat {
72 public:
73 int Run(int argc, char** argv);
74
75 private:
76 void RotateLogs();
77 void ProcessBuffer(struct log_msg* buf);
78 void PrintDividers(log_id_t log_id, bool print_dividers);
79 void SetupOutputAndSchedulingPolicy(bool blocking);
80 int SetLogFormat(const char* format_string);
WriteFully(const void * p,size_t n)81 void WriteFully(const void* p, size_t n) {
82 if (fwrite(p, 1, n, output_file_) != n) {
83 error(EXIT_FAILURE, errno, "Write to output file failed");
84 }
85 }
86
87 // Used for all options
88 std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
89 android_log_format_new(), &android_log_format_free};
90 // This isn't a unique_ptr because it's usually stdout;
91 // stdio's atexit handler ensures we flush on exit.
92 FILE* output_file_ = stdout;
93
94 // For logging to a file and log rotation
95 const char* output_file_name_ = nullptr;
96 size_t log_rotate_size_kb_ = 0; // 0 means "no log rotation"
97 size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
98 uint64_t out_byte_count_ = 0;
99
100 // For binary log buffers
101 int print_binary_ = 0;
102 std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
103 nullptr, &android_closeEventTagMap};
104 bool has_opened_event_tag_map_ = false;
105
106 // For the related --regex, --max-count, --print
107 std::unique_ptr<std::regex> regex_;
108 size_t max_count_ = 0; // 0 means "infinite"
109 size_t print_count_ = 0;
110 bool print_it_anyway_ = false;
111
112 // For PrintDividers()
113 bool print_dividers_ = false;
114 log_id_t last_printed_id_ = LOG_ID_MAX;
115 bool printed_start_[LOG_ID_MAX] = {};
116
117 bool debug_ = false;
118 };
119
pinLogFile(int fd,size_t sizeKB)120 static void pinLogFile(int fd, size_t sizeKB) {
121 // Ignore errors.
122 uint32_t set = 1;
123 ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
124 fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, (sizeKB << 10));
125 }
126
unpinLogFile(const char * pathname)127 static void unpinLogFile(const char* pathname) {
128 int fd = open(pathname, O_WRONLY | O_CLOEXEC);
129 if (fd != -1) {
130 // Ignore errors.
131 uint32_t set = 0;
132 ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
133 close(fd);
134 }
135 }
136
openLogFile(const char * path,size_t sizeKB)137 static FILE* openLogFile(const char* path, size_t sizeKB) {
138 int fd = open(path, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP);
139 if (fd == -1) {
140 error(EXIT_FAILURE, errno, "couldn't open output file '%s'", path);
141 }
142 pinLogFile(fd, sizeKB);
143 return fdopen(fd, "w");
144 }
145
RotateLogs()146 void Logcat::RotateLogs() {
147 // Can't rotate logs if we're not outputting to a file
148 if (!output_file_name_) return;
149
150 fclose(output_file_);
151 output_file_ = nullptr;
152
153 // Compute the maximum number of digits needed to count up to
154 // maxRotatedLogs in decimal. eg:
155 // maxRotatedLogs == 30
156 // -> log10(30) == 1.477
157 // -> maxRotationCountDigits == 2
158 int max_rotation_count_digits =
159 max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
160
161 for (int i = max_rotated_logs_; i > 0; i--) {
162 std::string file1 =
163 StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
164
165 std::string file0;
166 if (!(i - 1)) {
167 file0 = output_file_name_;
168 } else {
169 file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
170 }
171
172 if (!file0.length() || !file1.length()) {
173 perror("while rotating log files");
174 break;
175 }
176
177 unpinLogFile(file0.c_str());
178
179 if (rename(file0.c_str(), file1.c_str()) == -1 && errno != ENOENT) {
180 error(0, errno, "rename('%s', '%s') failed while rotating log files", file0.c_str(),
181 file1.c_str());
182 }
183 }
184
185 output_file_ = openLogFile(output_file_name_, log_rotate_size_kb_);
186 out_byte_count_ = 0;
187 }
188
ProcessBuffer(struct log_msg * buf)189 void Logcat::ProcessBuffer(struct log_msg* buf) {
190 AndroidLogEntry entry;
191 char binaryMsgBuf[1024] __attribute__((__uninitialized__));
192
193 bool is_binary =
194 buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
195 int err;
196 if (is_binary) {
197 if (!event_tag_map_ && !has_opened_event_tag_map_) {
198 event_tag_map_.reset(android_openEventTagMap(nullptr));
199 has_opened_event_tag_map_ = true;
200 }
201 // This causes entry to point to binaryMsgBuf!
202 err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
203 binaryMsgBuf, sizeof(binaryMsgBuf));
204
205 // printf(">>> pri=%d len=%d msg='%s'\n",
206 // entry.priority, entry.messageLen, entry.message);
207 } else {
208 err = android_log_processLogBuffer(&buf->entry, &entry);
209 }
210 if (err < 0 && !debug_) return;
211
212 if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
213 entry.priority)) {
214 bool match = !regex_ ||
215 std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
216
217 print_count_ += match;
218 if (match || print_it_anyway_) {
219 PrintDividers(buf->id(), print_dividers_);
220 out_byte_count_ += android_log_printLogLine(logformat_.get(), output_file_, &entry);
221 }
222 }
223
224 if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
225 RotateLogs();
226 }
227 }
228
PrintDividers(log_id_t log_id,bool print_dividers)229 void Logcat::PrintDividers(log_id_t log_id, bool print_dividers) {
230 if (log_id == last_printed_id_) {
231 return;
232 }
233 if (!printed_start_[log_id] || print_dividers) {
234 if (fprintf(output_file_, "--------- %s %s\n",
235 printed_start_[log_id] ? "switch to" : "beginning of",
236 android_log_id_to_name(log_id)) < 0) {
237 error(EXIT_FAILURE, errno, "Output error");
238 }
239 }
240 last_printed_id_ = log_id;
241 printed_start_[log_id] = true;
242 }
243
SetupOutputAndSchedulingPolicy(bool blocking)244 void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
245 if (!output_file_name_) return;
246
247 if (blocking) {
248 // Lower priority and set to batch scheduling if we are saving
249 // the logs into files and taking continuous content.
250 if (set_sched_policy(0, SP_BACKGROUND) < 0) {
251 fprintf(stderr, "failed to set background scheduling policy\n");
252 }
253
254 struct sched_param param = {};
255 if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
256 fprintf(stderr, "failed to set to batch scheduler\n");
257 }
258
259 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
260 fprintf(stderr, "failed set to priority\n");
261 }
262 }
263
264 output_file_ = openLogFile(output_file_name_, log_rotate_size_kb_);
265
266 struct stat sb;
267 if (fstat(fileno(output_file_), &sb) == -1) {
268 error(EXIT_FAILURE, errno, "Couldn't stat output file");
269 }
270 out_byte_count_ = sb.st_size;
271 }
272
273 // clang-format off
show_help()274 static void show_help() {
275 printf(R"logcat(
276 Usage: logcat [OPTION]... [FILTERSPEC]...
277
278 General options:
279
280 -b BUFFER, --buffer=BUFFER
281 Request alternate ring buffer(s). Options are:
282 main system radio events crash default all
283 Additionally, 'kernel' for userdebug and eng builds, and 'security' for
284 Device Owner installations.
285 Multiple -b parameters or comma separated list of buffers are
286 allowed. Buffers are interleaved.
287 Default is "main,system,crash,kernel".
288 -c, --clear
289 Clear (flush) the entire log and exit. With -f, clear the specified file
290 and its related rotated log files instead. With -L, clear pstore instead.
291 -d Dump the log and then exit (don't block).
292 -L, --last Dump logs from prior to last reboot from pstore.
293 --pid=PID Only print logs from the given pid.
294 --wrap
295 Sleep for 2 hours or until buffer about to wrap (whichever comes first).
296 Improves efficiency of polling by providing an about-to-wrap wakeup.
297
298 Formatting:
299
300 -v, --format=FORMAT Sets log print format. See FORMAT below.
301 -D, --dividers Print dividers between each log buffer.
302 -B, --binary Output the log in binary.
303
304 Output files:
305
306 -f, --file=FILE Log to FILE instead of stdout.
307 -r, --rotate-kbytes=N Rotate log every N KiB. Requires -f.
308 -n, --rotate-count=N Sets max number of rotated logs, default 4.
309 --id=<id>
310 Clears the associated files if the signature <id> for logging to file
311 changes.
312
313 Logd control:
314
315 These options send a control message to the logd daemon on device, print its
316 return message if applicable, then exit. They are incompatible with -L
317 because these attributes do not apply to pstore.
318
319 -g, --buffer-size
320 Get size of the ring buffers within logd.
321 -G, --buffer-size=SIZE
322 Set size of a ring buffer in logd. May suffix with K or M.
323 This can individually control each buffer's size with -b.
324 -p, --prune
325 Get prune rules. Each rule is specified as UID, UID/PID or /PID. A
326 '~' prefix indicates that elements matching the rule should be pruned
327 with higher priority otherwise they're pruned with lower priority. All
328 other pruning activity is oldest first. Special case ~! represents an
329 automatic pruning for the noisiest UID as determined by the current
330 statistics. Special case ~1000/! represents pruning of the worst PID
331 within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
332 -P, --prune='LIST ...'
333 Set prune rules, using same format as listed above. Must be quoted.
334 -S, --statistics
335 Output statistics. With --pid provides pid-specific stats.
336
337 Filtering:
338
339 -s Set default filter to silent (like filterspec '*:S').
340 -e, --regex=EXPR Only print lines matching ECMAScript regex.
341 -m, --max-count=N Exit after printing <count> lines.
342 --print With --regex and --max-count, prints all messages
343 even if they do not match the regex, but exits after
344 printing max-count matching lines.
345 -t N Print most recent <count> lines (implies -d).
346 -T N Print most recent <count> lines (does not imply -d).
347 -t TIME Print lines since specified time (implies -d).
348 -T TIME Print lines since specified time (not imply -d).
349 Time format is 'MM-DD hh:mm:ss.mmm...',
350 'YYYY-MM-DD hh:mm:ss.mmm...', or 'sssss.mmm...'.
351 --uid=UIDS
352 Only display log messages from UIDs in the comma-separated list UIDS.
353 UIDs must be numeric because no name lookup is performed.
354 Note that only root/log/system users can view logs from other users.
355
356 FILTERSPEC:
357
358 Filter specifications are a series of
359
360 <tag>[:priority]
361
362 where <tag> is a log component tag (or * for all) and priority is:
363
364 V Verbose (default for <tag>)
365 D Debug (default for '*')
366 I Info
367 W Warn
368 E Error
369 F Fatal
370 S Silent (suppress all output)
371
372 '*' by itself means '*:D' and <tag> by itself means <tag>:V.
373 If no '*' filterspec or -s on command line, all filter defaults to '*:V'.
374 '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.
375
376 If not specified on the command line, FILTERSPEC is $ANDROID_LOG_TAGS.
377
378 FORMAT:
379
380 Formats are a comma-separated sequence of verbs and adverbs.
381
382 Single format verbs:
383
384 brief Show priority, tag, and PID of the process issuing the message.
385 long Show all metadata fields and separate messages with blank lines.
386 process Show PID only.
387 raw Show the raw log message with no other metadata fields.
388 tag Show the priority and tag only.
389 thread Show priority, PID, and TID of the thread issuing the message.
390 threadtime Show the date, invocation time, priority, tag, PID, and TID of
391 the thread issuing the message. (This is the default.)
392 time Show the date, invocation time, priority, tag, and PID of the
393 process issuing the message.
394
395 Adverb modifiers can be used in combination:
396
397 color Show each priority with a different color.
398 descriptive Show event descriptions from event-log-tags database.
399 epoch Show time as seconds since 1970-01-01 (Unix epoch).
400 monotonic Show time as CPU seconds since boot.
401 printable Ensure that any binary logging content is escaped.
402 uid Show UID or Android ID of logged process (if permitted).
403 usec Show time with microsecond precision.
404 UTC Show time as UTC.
405 year Add the year to the displayed time.
406 zone Add the local timezone to the displayed time.
407 \"<ZONE>\" Print using this named timezone (experimental).
408
409 If not specified with -v on command line, FORMAT is $ANDROID_PRINTF_LOG or
410 defaults to "threadtime".
411 )logcat");
412 }
413 // clang-format on
414
SetLogFormat(const char * format_string)415 int Logcat::SetLogFormat(const char* format_string) {
416 AndroidLogPrintFormat format = android_log_formatFromString(format_string);
417
418 // invalid string?
419 if (format == FORMAT_OFF) return -1;
420
421 return android_log_setPrintFormat(logformat_.get(), format);
422 }
423
format_of_size(unsigned long value)424 static std::pair<unsigned long, const char*> format_of_size(unsigned long value) {
425 static const char multipliers[][3] = {{""}, {"Ki"}, {"Mi"}, {"Gi"}};
426 size_t i;
427 for (i = 0;
428 (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
429 value /= 1024, ++i)
430 ;
431 return std::make_pair(value, multipliers[i]);
432 }
433
parseTime(log_time & t,const char * cp)434 static char* parseTime(log_time& t, const char* cp) {
435 char* ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
436 if (ep) return ep;
437 ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
438 if (ep) return ep;
439 return t.strptime(cp, "%s.%q");
440 }
441
442 // Find last logged line in <outputFileName>, or <outputFileName>.1
lastLogTime(const char * outputFileName)443 static log_time lastLogTime(const char* outputFileName) {
444 log_time retval(log_time::EPOCH);
445 if (!outputFileName) return retval;
446
447 std::string directory;
448 const char* file = strrchr(outputFileName, '/');
449 if (!file) {
450 directory = ".";
451 file = outputFileName;
452 } else {
453 directory = std::string(outputFileName, file - outputFileName);
454 ++file;
455 }
456
457 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()),
458 closedir);
459 if (!dir.get()) return retval;
460
461 log_time now(CLOCK_REALTIME);
462
463 size_t len = strlen(file);
464 log_time modulo(0, NS_PER_SEC);
465 struct dirent* dp;
466
467 while (!!(dp = readdir(dir.get()))) {
468 if ((dp->d_type != DT_REG) || !!strncmp(dp->d_name, file, len) ||
469 (dp->d_name[len] && ((dp->d_name[len] != '.') ||
470 (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) {
471 continue;
472 }
473
474 std::string file_name = directory;
475 file_name += "/";
476 file_name += dp->d_name;
477 std::string file;
478 if (!android::base::ReadFileToString(file_name, &file)) continue;
479
480 bool found = false;
481 for (const auto& line : android::base::Split(file, "\n")) {
482 log_time t(log_time::EPOCH);
483 char* ep = parseTime(t, line.c_str());
484 if (!ep || (*ep != ' ')) continue;
485 // determine the time precision of the logs (eg: msec or usec)
486 for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
487 if (t.tv_nsec % (mod * 10)) {
488 modulo.tv_nsec = mod;
489 break;
490 }
491 }
492 // We filter any times later than current as we may not have the
493 // year stored with each log entry. Also, since it is possible for
494 // entries to be recorded out of order (very rare) we select the
495 // maximum we find just in case.
496 if ((t < now) && (t > retval)) {
497 retval = t;
498 found = true;
499 }
500 }
501 // We count on the basename file to be the definitive end, so stop here.
502 if (!dp->d_name[len] && found) break;
503 }
504 if (retval == log_time::EPOCH) return retval;
505 // tail_time prints matching or higher, round up by the modulo to prevent
506 // a replay of the last entry we have just checked.
507 retval += modulo;
508 return retval;
509 }
510
ReportErrorName(const std::string & name,bool allow_security,std::vector<std::string> * errors)511 void ReportErrorName(const std::string& name, bool allow_security,
512 std::vector<std::string>* errors) {
513 if (allow_security || name != "security") {
514 errors->emplace_back(name);
515 }
516 }
517
Run(int argc,char ** argv)518 int Logcat::Run(int argc, char** argv) {
519 bool hasSetLogFormat = false;
520 bool clearLog = false;
521 bool security_buffer_selected =
522 false; // Do not report errors on the security buffer unless it is explicitly named.
523 bool getLogSize = false;
524 bool getPruneList = false;
525 bool printStatistics = false;
526 unsigned long setLogSize = 0;
527 const char* setPruneList = nullptr;
528 const char* setId = nullptr;
529 int mode = 0;
530 std::string forceFilters;
531 size_t tail_lines = 0;
532 log_time tail_time(log_time::EPOCH);
533 size_t pid = 0;
534 bool got_t = false;
535 unsigned id_mask = 0;
536 std::set<uid_t> uids;
537
538 if (argc == 2 && !strcmp(argv[1], "--help")) {
539 show_help();
540 return EXIT_SUCCESS;
541 }
542
543 // meant to catch comma-delimited values, but cast a wider
544 // net for stability dealing with possible mistaken inputs.
545 static const char delimiters[] = ",:; \t\n\r\f";
546
547 optind = 0;
548 while (true) {
549 int option_index = 0;
550 // list of long-argument only strings for later comparison
551 static const char pid_str[] = "pid";
552 static const char debug_str[] = "debug";
553 static const char id_str[] = "id";
554 static const char wrap_str[] = "wrap";
555 static const char print_str[] = "print";
556 static const char uid_str[] = "uid";
557 // clang-format off
558 static const struct option long_options[] = {
559 { "binary", no_argument, nullptr, 'B' },
560 { "buffer", required_argument, nullptr, 'b' },
561 { "buffer-size", optional_argument, nullptr, 'g' },
562 { "clear", no_argument, nullptr, 'c' },
563 { debug_str, no_argument, nullptr, 0 },
564 { "dividers", no_argument, nullptr, 'D' },
565 { "file", required_argument, nullptr, 'f' },
566 { "format", required_argument, nullptr, 'v' },
567 // hidden and undocumented reserved alias for --regex
568 { "grep", required_argument, nullptr, 'e' },
569 // hidden and undocumented reserved alias for --max-count
570 { "head", required_argument, nullptr, 'm' },
571 { "help", no_argument, nullptr, 'h' },
572 { id_str, required_argument, nullptr, 0 },
573 { "last", no_argument, nullptr, 'L' },
574 { "max-count", required_argument, nullptr, 'm' },
575 { pid_str, required_argument, nullptr, 0 },
576 { print_str, no_argument, nullptr, 0 },
577 { "prune", optional_argument, nullptr, 'p' },
578 { "regex", required_argument, nullptr, 'e' },
579 { "rotate-count", required_argument, nullptr, 'n' },
580 { "rotate-kbytes", required_argument, nullptr, 'r' },
581 { "statistics", no_argument, nullptr, 'S' },
582 // hidden and undocumented reserved alias for -t
583 { "tail", required_argument, nullptr, 't' },
584 { uid_str, required_argument, nullptr, 0 },
585 // support, but ignore and do not document, the optional argument
586 { wrap_str, optional_argument, nullptr, 0 },
587 { nullptr, 0, nullptr, 0 }
588 };
589 // clang-format on
590
591 int c = getopt_long(argc, argv, ":cdDhLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", long_options,
592 &option_index);
593 if (c == -1) break;
594
595 switch (c) {
596 case 0:
597 // only long options
598 if (long_options[option_index].name == pid_str) {
599 if (pid != 0) {
600 error(EXIT_FAILURE, 0, "Only one --pid argument can be provided.");
601 }
602
603 if (!ParseUint(optarg, &pid) || pid < 1) {
604 error(EXIT_FAILURE, 0, "%s %s out of range.",
605 long_options[option_index].name, optarg);
606 }
607 break;
608 }
609 if (long_options[option_index].name == wrap_str) {
610 mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK;
611 // ToDo: implement API that supports setting a wrap timeout
612 size_t timeout = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
613 if (optarg && (!ParseUint(optarg, &timeout) || timeout < 1)) {
614 error(EXIT_FAILURE, 0, "%s %s out of range.",
615 long_options[option_index].name, optarg);
616 }
617 if (timeout != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
618 fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
619 long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
620 timeout);
621 }
622 break;
623 }
624 if (long_options[option_index].name == print_str) {
625 print_it_anyway_ = true;
626 break;
627 }
628 if (long_options[option_index].name == debug_str) {
629 debug_ = true;
630 break;
631 }
632 if (long_options[option_index].name == id_str) {
633 setId = (optarg && optarg[0]) ? optarg : nullptr;
634 }
635 if (long_options[option_index].name == uid_str) {
636 auto uid_strings = Split(optarg, delimiters);
637 for (const auto& uid_string : uid_strings) {
638 uid_t uid;
639 if (!ParseUint(uid_string, &uid)) {
640 error(EXIT_FAILURE, 0, "Unable to parse UID '%s'", uid_string.c_str());
641 }
642 uids.emplace(uid);
643 }
644 break;
645 }
646 break;
647
648 case 's':
649 // default to all silent
650 android_log_addFilterRule(logformat_.get(), "*:s");
651 break;
652
653 case 'c':
654 clearLog = true;
655 break;
656
657 case 'L':
658 mode |= ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
659 break;
660
661 case 'd':
662 mode |= ANDROID_LOG_NONBLOCK;
663 break;
664
665 case 't':
666 got_t = true;
667 mode |= ANDROID_LOG_NONBLOCK;
668 FALLTHROUGH_INTENDED;
669 case 'T':
670 if (strspn(optarg, "0123456789") != strlen(optarg)) {
671 char* cp = parseTime(tail_time, optarg);
672 if (!cp) {
673 error(EXIT_FAILURE, 0, "-%c '%s' not in time format.", c, optarg);
674 }
675 if (*cp) {
676 char ch = *cp;
677 *cp = '\0';
678 fprintf(stderr, "WARNING: -%c '%s' '%c%s' time truncated\n", c, optarg, ch,
679 cp + 1);
680 *cp = ch;
681 }
682 } else {
683 if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
684 fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
685 tail_lines = 1;
686 }
687 }
688 break;
689
690 case 'D':
691 print_dividers_ = true;
692 break;
693
694 case 'e':
695 regex_.reset(new std::regex(optarg));
696 break;
697
698 case 'm': {
699 if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
700 error(EXIT_FAILURE, 0, "-%c '%s' isn't an integer greater than zero.", c,
701 optarg);
702 }
703 } break;
704
705 case 'g':
706 if (!optarg) {
707 getLogSize = true;
708 break;
709 }
710 FALLTHROUGH_INTENDED;
711
712 case 'G': {
713 if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
714 error(EXIT_FAILURE, 0, "-G must be specified as <num><multiplier>.");
715 }
716 } break;
717
718 case 'p':
719 if (!optarg) {
720 getPruneList = true;
721 break;
722 }
723 FALLTHROUGH_INTENDED;
724
725 case 'P':
726 setPruneList = optarg;
727 break;
728
729 case 'b':
730 for (const auto& buffer : Split(optarg, delimiters)) {
731 if (buffer == "default") {
732 id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
733 } else if (buffer == "all") {
734 id_mask = -1;
735 } else {
736 log_id_t log_id = android_name_to_log_id(buffer.c_str());
737 if (log_id >= LOG_ID_MAX) {
738 error(EXIT_FAILURE, 0, "Unknown buffer '%s' listed for -b.",
739 buffer.c_str());
740 }
741 if (log_id == LOG_ID_SECURITY) {
742 security_buffer_selected = true;
743 }
744 id_mask |= (1 << log_id);
745 }
746 }
747 break;
748
749 case 'B':
750 print_binary_ = 1;
751 break;
752
753 case 'f':
754 if ((tail_time == log_time::EPOCH) && !tail_lines) {
755 tail_time = lastLogTime(optarg);
756 }
757 // redirect output to a file
758 output_file_name_ = optarg;
759 break;
760
761 case 'r':
762 if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
763 error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -r.", optarg);
764 }
765 break;
766
767 case 'n':
768 if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
769 error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -n.", optarg);
770 }
771 break;
772
773 case 'v':
774 for (const auto& arg : Split(optarg, delimiters)) {
775 int err = SetLogFormat(arg.c_str());
776 if (err < 0) {
777 error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -v.", arg.c_str());
778 }
779 if (err) hasSetLogFormat = true;
780 }
781 break;
782
783 case 'S':
784 printStatistics = true;
785 break;
786
787 case ':':
788 error(EXIT_FAILURE, 0, "Option '%s' needs an argument.", argv[optind - 1]);
789 break;
790
791 case 'h':
792 show_help();
793 return EXIT_SUCCESS;
794
795 case '?':
796 error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind]);
797 break;
798
799 default:
800 error(EXIT_FAILURE, 0, "Unknown getopt_long() result '%c'.", c);
801 }
802 }
803
804 if (max_count_ && got_t) {
805 error(EXIT_FAILURE, 0, "Cannot use -m (--max-count) and -t together.");
806 }
807 if (print_it_anyway_ && (!regex_ || !max_count_)) {
808 // One day it would be nice if --print -v color and --regex <expr>
809 // could play with each other and show regex highlighted content.
810 fprintf(stderr,
811 "WARNING: "
812 "--print ignored, to be used in combination with\n"
813 " "
814 "--regex <expr> and --max-count <N>\n");
815 print_it_anyway_ = false;
816 }
817
818 // If no buffers are specified, default to using these buffers.
819 if (id_mask == 0) {
820 id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
821 (1 << LOG_ID_KERNEL);
822 }
823
824 if (log_rotate_size_kb_ != 0 && !output_file_name_) {
825 error(EXIT_FAILURE, 0, "-r requires -f as well.");
826 }
827
828 if (setId != 0) {
829 if (!output_file_name_) {
830 error(EXIT_FAILURE, 0, "--id='%s' requires -f as well.", setId);
831 }
832
833 std::string file_name = StringPrintf("%s.id", output_file_name_);
834 std::string file;
835 bool file_ok = android::base::ReadFileToString(file_name, &file);
836 android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
837 getuid(), getgid());
838 if (!file_ok || !file.compare(setId)) setId = nullptr;
839 }
840
841 if (!hasSetLogFormat) {
842 const char* logFormat = getenv("ANDROID_PRINTF_LOG");
843
844 if (!!logFormat) {
845 for (const auto& arg : Split(logFormat, delimiters)) {
846 int err = SetLogFormat(arg.c_str());
847 // environment should not cause crash of logcat
848 if (err < 0) {
849 fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
850 }
851 if (err > 0) hasSetLogFormat = true;
852 }
853 }
854 if (!hasSetLogFormat) {
855 SetLogFormat("threadtime");
856 }
857 }
858
859 if (forceFilters.size()) {
860 int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
861 if (err < 0) {
862 error(EXIT_FAILURE, 0, "Invalid filter expression in logcat args.");
863 }
864 } else if (argc == optind) {
865 // Add from environment variable
866 const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
867
868 if (!!env_tags_orig) {
869 int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
870
871 if (err < 0) {
872 error(EXIT_FAILURE, 0, "Invalid filter expression in ANDROID_LOG_TAGS.");
873 }
874 }
875 } else {
876 // Add from commandline
877 for (int i = optind ; i < argc ; i++) {
878 int err = android_log_addFilterString(logformat_.get(), argv[i]);
879 if (err < 0) {
880 error(EXIT_FAILURE, 0, "Invalid filter expression '%s'.", argv[i]);
881 }
882 }
883 }
884
885 if (mode & ANDROID_LOG_PSTORE) {
886 if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
887 error(EXIT_FAILURE, 0, "-L is incompatible with -g/-G, -S, and -p/-P.");
888 }
889 if (clearLog) {
890 if (output_file_name_) {
891 error(EXIT_FAILURE, 0, "-c is ambiguous with both -f and -L specified.");
892 }
893 unlink("/sys/fs/pstore/pmsg-ramoops-0");
894 return EXIT_SUCCESS;
895 }
896 }
897
898 if (output_file_name_) {
899 if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
900 error(EXIT_FAILURE, 0, "-f is incompatible with -g/-G, -S, and -p/-P.");
901 }
902
903 if (clearLog || setId) {
904 int max_rotation_count_digits =
905 max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
906
907 for (int i = max_rotated_logs_; i >= 0; --i) {
908 std::string file;
909
910 if (!i) {
911 file = output_file_name_;
912 } else {
913 file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
914 }
915
916 int err = unlink(file.c_str());
917
918 if (err < 0 && errno != ENOENT) {
919 fprintf(stderr, "failed to delete log file '%s': %s\n", file.c_str(),
920 strerror(errno));
921 }
922 }
923 }
924
925 if (clearLog) {
926 return EXIT_SUCCESS;
927 }
928 }
929
930 std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
931 nullptr, &android_logger_list_free};
932 if (tail_time != log_time::EPOCH) {
933 logger_list.reset(android_logger_list_alloc_time(mode, tail_time, pid));
934 } else {
935 logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));
936 }
937 // We have three orthogonal actions below to clear, set log size and
938 // get log size. All sharing the same iteration loop.
939 std::vector<std::string> open_device_failures;
940 std::vector<std::string> clear_failures;
941 std::vector<std::string> set_size_failures;
942 std::vector<std::string> get_size_failures;
943
944 for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
945 if (!(id_mask & (1 << i))) continue;
946 const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
947
948 auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
949 if (logger == nullptr) {
950 ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
951 continue;
952 }
953
954 if (clearLog) {
955 if (android_logger_clear(logger)) {
956 ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
957 }
958 }
959
960 if (setLogSize) {
961 if (android_logger_set_log_size(logger, setLogSize)) {
962 ReportErrorName(buffer_name, security_buffer_selected, &set_size_failures);
963 }
964 }
965
966 if (getLogSize) {
967 long size = android_logger_get_log_size(logger);
968 long readable = android_logger_get_log_readable_size(logger);
969 long consumed = android_logger_get_log_consumed_size(logger);
970
971 if (size < 0 || readable < 0) {
972 ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
973 } else {
974 auto size_format = format_of_size(size);
975 auto readable_format = format_of_size(readable);
976 auto consumed_format = format_of_size(consumed);
977 std::string str = android::base::StringPrintf(
978 "%s: ring buffer is %lu %sB (%lu %sB consumed, %lu %sB readable),"
979 " max entry is %d B, max payload is %d B\n",
980 buffer_name, size_format.first, size_format.second, consumed_format.first,
981 consumed_format.second, readable_format.first, readable_format.second,
982 (int)LOGGER_ENTRY_MAX_LEN, (int)LOGGER_ENTRY_MAX_PAYLOAD);
983 WriteFully(str.data(), str.length());
984 }
985 }
986 }
987
988 // report any errors in the above loop and exit
989 if (!open_device_failures.empty()) {
990 error(EXIT_FAILURE, 0, "Unable to open log device%s '%s'.",
991 open_device_failures.size() > 1 ? "s" : "", Join(open_device_failures, ",").c_str());
992 }
993 if (!clear_failures.empty()) {
994 error(EXIT_FAILURE, 0, "failed to clear the '%s' log%s.", Join(clear_failures, ",").c_str(),
995 clear_failures.size() > 1 ? "s" : "");
996 }
997 if (!set_size_failures.empty()) {
998 error(EXIT_FAILURE, 0, "failed to set the '%s' log size%s.",
999 Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
1000 }
1001 if (!get_size_failures.empty()) {
1002 error(EXIT_FAILURE, 0, "failed to get the readable '%s' log size%s.",
1003 Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
1004 }
1005
1006 if (setPruneList) {
1007 size_t len = strlen(setPruneList);
1008 if (android_logger_set_prune_list(logger_list.get(), setPruneList, len)) {
1009 error(EXIT_FAILURE, 0, "Failed to set the prune list.");
1010 }
1011 return EXIT_SUCCESS;
1012 }
1013
1014 if (printStatistics || getPruneList) {
1015 std::string buf(8192, '\0');
1016 size_t ret_length = 0;
1017 int retry = 32;
1018
1019 for (; retry >= 0; --retry) {
1020 if (getPruneList) {
1021 android_logger_get_prune_list(logger_list.get(), buf.data(), buf.size());
1022 } else {
1023 android_logger_get_statistics(logger_list.get(), buf.data(), buf.size());
1024 }
1025
1026 ret_length = atol(buf.c_str());
1027 if (ret_length < 3) {
1028 error(EXIT_FAILURE, 0, "Failed to read data.");
1029 }
1030
1031 if (ret_length < buf.size()) {
1032 break;
1033 }
1034
1035 buf.resize(ret_length + 1);
1036 }
1037
1038 if (retry < 0) {
1039 error(EXIT_FAILURE, 0, "Failed to read data.");
1040 }
1041
1042 buf.resize(ret_length);
1043 if (buf.back() == '\f') {
1044 buf.pop_back();
1045 }
1046
1047 // Remove the byte count prefix
1048 const char* cp = buf.c_str();
1049 while (isdigit(*cp)) ++cp;
1050 if (*cp == '\n') ++cp;
1051
1052 WriteFully(cp, strlen(cp));
1053 return EXIT_SUCCESS;
1054 }
1055
1056 if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
1057
1058 bool blocking = !(mode & ANDROID_LOG_NONBLOCK);
1059 SetupOutputAndSchedulingPolicy(blocking);
1060
1061 if (!WaitForProperty("logd.ready", "true", std::chrono::seconds(1))) {
1062 error(EXIT_FAILURE, 0, "Failed to wait for logd.ready to become true. logd not running?");
1063 }
1064
1065 while (!max_count_ || print_count_ < max_count_) {
1066 struct log_msg log_msg;
1067 int ret = android_logger_list_read(logger_list.get(), &log_msg);
1068 if (!ret) {
1069 error(EXIT_FAILURE, 0, R"init(Unexpected EOF!
1070
1071 This means that either the device shut down, logd crashed, or this instance of logcat was unable to read log
1072 messages as quickly as they were being produced.
1073
1074 If you have enabled significant logging, look into using the -G option to increase log buffer sizes.)init");
1075 }
1076
1077 if (ret < 0) {
1078 if (ret == -EAGAIN) break;
1079
1080 if (ret == -EIO) {
1081 error(EXIT_FAILURE, 0, "Unexpected EOF!");
1082 }
1083 if (ret == -EINVAL) {
1084 error(EXIT_FAILURE, 0, "Unexpected length.");
1085 }
1086 error(EXIT_FAILURE, errno, "Logcat read failure");
1087 }
1088
1089 if (log_msg.id() > LOG_ID_MAX) {
1090 error(EXIT_FAILURE, 0, "Unexpected log id (%d) over LOG_ID_MAX (%d).", log_msg.id(),
1091 LOG_ID_MAX);
1092 }
1093
1094 if (!uids.empty() && uids.count(log_msg.entry.uid) == 0) {
1095 continue;
1096 }
1097
1098 if (print_binary_) {
1099 WriteFully(&log_msg, log_msg.len());
1100 } else {
1101 ProcessBuffer(&log_msg);
1102 }
1103 if (blocking && output_file_ == stdout) fflush(stdout);
1104 }
1105 return EXIT_SUCCESS;
1106 }
1107
main(int argc,char ** argv)1108 int main(int argc, char** argv) {
1109 Logcat logcat;
1110 return logcat.Run(argc, argv);
1111 }
1112