• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &param) < 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