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