1 /*
2  * Copyright (C) 2006-2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <ctype.h>
18 #include <dirent.h>
19 #include <errno.h>
20 #include <error.h>
21 #include <fcntl.h>
22 #include <getopt.h>
23 #include <math.h>
24 #include <sched.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/cdefs.h>
30 #include <sys/ioctl.h>
31 #include <sys/resource.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <time.h>
35 #include <unistd.h>
36 
37 #include <memory>
38 #include <regex>
39 #include <set>
40 #include <string>
41 #include <utility>
42 #include <vector>
43 
44 #include <android-base/file.h>
45 #include <android-base/macros.h>
46 #include <android-base/parseint.h>
47 #include <android-base/properties.h>
48 #include <android-base/stringprintf.h>
49 #include <android-base/strings.h>
50 #include <android-base/unique_fd.h>
51 #include <android/log.h>
52 #include <log/event_tag_map.h>
53 #include <log/log_id.h>
54 #include <log/log_read.h>
55 #include <log/logprint.h>
56 #include <private/android_logger.h>
57 #include <processgroup/sched_policy.h>
58 #include <system/thread_defs.h>
59 
60 #define DEFAULT_MAX_ROTATED_LOGS 4
61 
62 using android::base::Join;
63 using android::base::ParseByteCount;
64 using android::base::ParseUint;
65 using android::base::Split;
66 using android::base::StringPrintf;
67 
68 class Logcat {
69   public:
70     int Run(int argc, char** argv);
71 
72   private:
73     void RotateLogs();
74     void ProcessBuffer(struct log_msg* buf);
75     void PrintDividers(log_id_t log_id, bool print_dividers);
76     void SetupOutputAndSchedulingPolicy(bool blocking);
77     int SetLogFormat(const char* format_string);
78 
79     // Used for all options
80     android::base::unique_fd output_fd_{dup(STDOUT_FILENO)};
81     std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
82             android_log_format_new(), &android_log_format_free};
83 
84     // For logging to a file and log rotation
85     const char* output_file_name_ = nullptr;
86     size_t log_rotate_size_kb_ = 0;                       // 0 means "no log rotation"
87     size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS;  // 0 means "unbounded"
88     size_t out_byte_count_ = 0;
89 
90     // For binary log buffers
91     int print_binary_ = 0;
92     std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
93             nullptr, &android_closeEventTagMap};
94     bool has_opened_event_tag_map_ = false;
95 
96     // For the related --regex, --max-count, --print
97     std::unique_ptr<std::regex> regex_;
98     size_t max_count_ = 0;  // 0 means "infinite"
99     size_t print_count_ = 0;
100     bool print_it_anyways_ = false;
101 
102     // For PrintDividers()
103     log_id_t last_printed_id_ = LOG_ID_MAX;
104     bool printed_start_[LOG_ID_MAX] = {};
105 
106     bool debug_ = false;
107 };
108 
109 #ifndef F2FS_IOC_SET_PIN_FILE
110 #define F2FS_IOCTL_MAGIC       0xf5
111 #define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
112 #endif
113 
openLogFile(const char * pathname,size_t sizeKB)114 static int openLogFile(const char* pathname, size_t sizeKB) {
115     int fd = open(pathname, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP);
116     if (fd < 0) {
117         return fd;
118     }
119 
120     // no need to check errors
121     __u32 set = 1;
122     ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
123     fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, (sizeKB << 10));
124     return fd;
125 }
126 
closeLogFile(const char * pathname)127 static void closeLogFile(const char* pathname) {
128     int fd = open(pathname, O_WRONLY | O_CLOEXEC);
129     if (fd == -1) {
130         return;
131     }
132 
133     // no need to check errors
134     __u32 set = 0;
135     ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
136     close(fd);
137 }
138 
RotateLogs()139 void Logcat::RotateLogs() {
140     // Can't rotate logs if we're not outputting to a file
141     if (!output_file_name_) return;
142 
143     output_fd_.reset();
144 
145     // Compute the maximum number of digits needed to count up to
146     // maxRotatedLogs in decimal.  eg:
147     // maxRotatedLogs == 30
148     //   -> log10(30) == 1.477
149     //   -> maxRotationCountDigits == 2
150     int max_rotation_count_digits =
151             max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
152 
153     for (int i = max_rotated_logs_; i > 0; i--) {
154         std::string file1 =
155                 StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
156 
157         std::string file0;
158         if (!(i - 1)) {
159             file0 = output_file_name_;
160         } else {
161             file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
162         }
163 
164         if (!file0.length() || !file1.length()) {
165             perror("while rotating log files");
166             break;
167         }
168 
169         closeLogFile(file0.c_str());
170 
171         int err = rename(file0.c_str(), file1.c_str());
172 
173         if (err < 0 && errno != ENOENT) {
174             perror("while rotating log files");
175         }
176     }
177 
178     output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
179 
180     if (!output_fd_.ok()) {
181         error(EXIT_FAILURE, errno, "Couldn't open output file");
182     }
183 
184     out_byte_count_ = 0;
185 }
186 
ProcessBuffer(struct log_msg * buf)187 void Logcat::ProcessBuffer(struct log_msg* buf) {
188     int bytesWritten = 0;
189     int err;
190     AndroidLogEntry entry;
191     char binaryMsgBuf[1024];
192 
193     bool is_binary =
194             buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
195 
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         err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
202                                                  binaryMsgBuf, sizeof(binaryMsgBuf));
203         // printf(">>> pri=%d len=%d msg='%s'\n",
204         //    entry.priority, entry.messageLen, entry.message);
205     } else {
206         err = android_log_processLogBuffer(&buf->entry, &entry);
207     }
208     if (err < 0 && !debug_) return;
209 
210     if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
211                                     entry.priority)) {
212         bool match = !regex_ ||
213                      std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
214 
215         print_count_ += match;
216         if (match || print_it_anyways_) {
217             bytesWritten = android_log_printLogLine(logformat_.get(), output_fd_.get(), &entry);
218 
219             if (bytesWritten < 0) {
220                 error(EXIT_FAILURE, 0, "Output error.");
221             }
222         }
223     }
224 
225     out_byte_count_ += bytesWritten;
226 
227     if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
228         RotateLogs();
229     }
230 }
231 
PrintDividers(log_id_t log_id,bool print_dividers)232 void Logcat::PrintDividers(log_id_t log_id, bool print_dividers) {
233     if (log_id == last_printed_id_ || print_binary_) {
234         return;
235     }
236     if (!printed_start_[log_id] || print_dividers) {
237         if (dprintf(output_fd_.get(), "--------- %s %s\n",
238                     printed_start_[log_id] ? "switch to" : "beginning of",
239                     android_log_id_to_name(log_id)) < 0) {
240             error(EXIT_FAILURE, errno, "Output error");
241         }
242     }
243     last_printed_id_ = log_id;
244     printed_start_[log_id] = true;
245 }
246 
SetupOutputAndSchedulingPolicy(bool blocking)247 void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
248     if (!output_file_name_) return;
249 
250     if (blocking) {
251         // Lower priority and set to batch scheduling if we are saving
252         // the logs into files and taking continuous content.
253         if (set_sched_policy(0, SP_BACKGROUND) < 0) {
254             fprintf(stderr, "failed to set background scheduling policy\n");
255         }
256 
257         struct sched_param param = {};
258         if (sched_setscheduler((pid_t)0, SCHED_BATCH, &param) < 0) {
259             fprintf(stderr, "failed to set to batch scheduler\n");
260         }
261 
262         if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
263             fprintf(stderr, "failed set to priority\n");
264         }
265     }
266 
267     output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
268 
269     if (!output_fd_.ok()) {
270         error(EXIT_FAILURE, errno, "Couldn't open output file");
271     }
272 
273     struct stat statbuf;
274     if (fstat(output_fd_.get(), &statbuf) == -1) {
275         error(EXIT_FAILURE, errno, "Couldn't get output file stat");
276     }
277 
278     if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
279         error(EXIT_FAILURE, 0, "Invalid output file stat.");
280     }
281 
282     out_byte_count_ = statbuf.st_size;
283 }
284 
285 // clang-format off
show_help()286 static void show_help() {
287     const char* cmd = getprogname();
288 
289     fprintf(stderr, "Usage: %s [options] [filterspecs]\n", cmd);
290 
291     fprintf(stderr, R"init(
292 General options:
293   -b, --buffer=<buffer>       Request alternate ring buffer(s):
294                                 main system radio events crash default all
295                               Additionally, 'kernel' for userdebug and eng builds, and
296                               'security' for Device Owner installations.
297                               Multiple -b parameters or comma separated list of buffers are
298                               allowed. Buffers are interleaved.
299                               Default -b main,system,crash,kernel.
300   -L, --last                  Dump logs from prior to last reboot from pstore.
301   -c, --clear                 Clear (flush) the entire log and exit.
302                               if -f is specified, clear the specified file and its related rotated
303                               log files instead.
304                               if -L is specified, clear pstore log instead.
305   -d                          Dump the log and then exit (don't block).
306   --pid=<pid>                 Only print logs from the given pid.
307   --wrap                      Sleep for 2 hours or when buffer about to wrap whichever
308                               comes first. Improves efficiency of polling by providing
309                               an about-to-wrap wakeup.
310 
311 Formatting:
312   -v, --format=<format>       Sets log print format verb and adverbs, where <format> is one of:
313                                 brief help long process raw tag thread threadtime time
314                               Modifying adverbs can be added:
315                                 color descriptive epoch monotonic printable uid usec UTC year zone
316                               Multiple -v parameters or comma separated list of format and format
317                               modifiers are allowed.
318   -D, --dividers              Print dividers between each log buffer.
319   -B, --binary                Output the log in binary.
320 
321 Outfile files:
322   -f, --file=<file>           Log to file instead of stdout.
323   -r, --rotate-kbytes=<n>     Rotate log every <n> kbytes. Requires -f option.
324   -n, --rotate-count=<count>  Sets max number of rotated logs to <count>, default 4.
325   --id=<id>                   If the signature <id> for logging to file changes, then clear the
326                               associated files and continue.
327 
328 Logd control:
329  These options send a control message to the logd daemon on device, print its return message if
330  applicable, then exit. They are incompatible with -L, as these attributes do not apply to pstore.
331   -g, --buffer-size           Get the size of the ring buffers within logd.
332   -G, --buffer-size=<size>    Set size of a ring buffer in logd. May suffix with K or M.
333                               This can individually control each buffer's size with -b.
334   -S, --statistics            Output statistics.
335                               --pid can be used to provide pid specific stats.
336   -p, --prune                 Print prune rules. Each rule is specified as UID, UID/PID or /PID. A
337                               '~' prefix indicates that elements matching the rule should be pruned
338                               with higher priority otherwise they're pruned with lower priority. All
339                               other pruning activity is oldest first. Special case ~! represents an
340                               automatic pruning for the noisiest UID as determined by the current
341                               statistics.  Special case ~1000/! represents pruning of the worst PID
342                               within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
343   -P, --prune='<list> ...'    Set prune rules, using same format as listed above. Must be quoted.
344 
345 Filtering:
346   -s                          Set default filter to silent. Equivalent to filterspec '*:S'
347   -e, --regex=<expr>          Only print lines where the log message matches <expr> where <expr> is
348                               an ECMAScript regular expression.
349   -m, --max-count=<count>     Quit after printing <count> lines. This is meant to be paired with
350                               --regex, but will work on its own.
351   --print                     This option is only applicable when --regex is set and only useful if
352                               --max-count is also provided.
353                               With --print, logcat will print all messages even if they do not
354                               match the regex. Logcat will quit after printing the max-count number
355                               of lines that match the regex.
356   -t <count>                  Print only the most recent <count> lines (implies -d).
357   -t '<time>'                 Print the lines since specified time (implies -d).
358   -T <count>                  Print only the most recent <count> lines (does not imply -d).
359   -T '<time>'                 Print the lines since specified time (not imply -d).
360                               count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
361                               'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format.
362   --uid=<uids>                Only display log messages from UIDs present in the comma separate list
363                               <uids>. No name look-up is performed, so UIDs must be provided as
364                               numeric values. This option is only useful for the 'root', 'log', and
365                               'system' users since only those users can view logs from other users.
366 )init");
367 
368     fprintf(stderr, "\nfilterspecs are a series of \n"
369                    "  <tag>[:priority]\n\n"
370                    "where <tag> is a log component tag (or * for all) and priority is:\n"
371                    "  V    Verbose (default for <tag>)\n"
372                    "  D    Debug (default for '*')\n"
373                    "  I    Info\n"
374                    "  W    Warn\n"
375                    "  E    Error\n"
376                    "  F    Fatal\n"
377                    "  S    Silent (suppress all output)\n"
378                    "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
379                    "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
380                    "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
381                    "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
382                    "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
383                    "or defaults to \"threadtime\"\n\n");
384 }
385 
show_format_help()386 static void show_format_help() {
387     fprintf(stderr,
388         "-v <format>, --format=<format> options:\n"
389         "  Sets log print format verb and adverbs, where <format> is:\n"
390         "    brief long process raw tag thread threadtime time\n"
391         "  and individually flagged modifying adverbs can be added:\n"
392         "    color descriptive epoch monotonic printable uid usec UTC year zone\n"
393         "\nSingle format verbs:\n"
394         "  brief      — Display priority/tag and PID of the process issuing the message.\n"
395         "  long       — Display all metadata fields, separate messages with blank lines.\n"
396         "  process    — Display PID only.\n"
397         "  raw        — Display the raw log message, with no other metadata fields.\n"
398         "  tag        — Display the priority/tag only.\n"
399         "  thread     — Display priority, PID and TID of process issuing the message.\n"
400         "  threadtime — Display the date, invocation time, priority, tag, and the PID\n"
401         "               and TID of the thread issuing the message. (the default format).\n"
402         "  time       — Display the date, invocation time, priority/tag, and PID of the\n"
403         "             process issuing the message.\n"
404         "\nAdverb modifiers can be used in combination:\n"
405         "  color       — Display in highlighted color to match priority. i.e. \x1B[39mVERBOSE\n"
406         "                \x1B[34mDEBUG \x1B[32mINFO \x1B[33mWARNING \x1B[31mERROR FATAL\x1B[0m\n"
407         "  descriptive — events logs only, descriptions from event-log-tags database.\n"
408         "  epoch       — Display time as seconds since Jan 1 1970.\n"
409         "  monotonic   — Display time as cpu seconds since last boot.\n"
410         "  printable   — Ensure that any binary logging content is escaped.\n"
411         "  uid         — If permitted, display the UID or Android ID of logged process.\n"
412         "  usec        — Display time down the microsecond precision.\n"
413         "  UTC         — Display time as UTC.\n"
414         "  year        — Add the year to the displayed time.\n"
415         "  zone        — Add the local timezone to the displayed time.\n"
416         "  \"<zone>\"    — Print using this public named timezone (experimental).\n\n"
417     );
418 }
419 // clang-format on
420 
SetLogFormat(const char * format_string)421 int Logcat::SetLogFormat(const char* format_string) {
422     AndroidLogPrintFormat format = android_log_formatFromString(format_string);
423 
424     // invalid string?
425     if (format == FORMAT_OFF) return -1;
426 
427     return android_log_setPrintFormat(logformat_.get(), format);
428 }
429 
format_of_size(unsigned long value)430 static std::pair<unsigned long, const char*> format_of_size(unsigned long value) {
431     static const char multipliers[][3] = {{""}, {"Ki"}, {"Mi"}, {"Gi"}};
432     size_t i;
433     for (i = 0;
434          (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
435          value /= 1024, ++i)
436         ;
437     return std::make_pair(value, multipliers[i]);
438 }
439 
parseTime(log_time & t,const char * cp)440 static char* parseTime(log_time& t, const char* cp) {
441     char* ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
442     if (ep) return ep;
443     ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
444     if (ep) return ep;
445     return t.strptime(cp, "%s.%q");
446 }
447 
448 // Find last logged line in <outputFileName>, or <outputFileName>.1
lastLogTime(const char * outputFileName)449 static log_time lastLogTime(const char* outputFileName) {
450     log_time retval(log_time::EPOCH);
451     if (!outputFileName) return retval;
452 
453     std::string directory;
454     const char* file = strrchr(outputFileName, '/');
455     if (!file) {
456         directory = ".";
457         file = outputFileName;
458     } else {
459         directory = std::string(outputFileName, file - outputFileName);
460         ++file;
461     }
462 
463     std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()),
464                                             closedir);
465     if (!dir.get()) return retval;
466 
467     log_time now(CLOCK_REALTIME);
468 
469     size_t len = strlen(file);
470     log_time modulo(0, NS_PER_SEC);
471     struct dirent* dp;
472 
473     while (!!(dp = readdir(dir.get()))) {
474         if ((dp->d_type != DT_REG) || !!strncmp(dp->d_name, file, len) ||
475             (dp->d_name[len] && ((dp->d_name[len] != '.') ||
476                                  (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) {
477             continue;
478         }
479 
480         std::string file_name = directory;
481         file_name += "/";
482         file_name += dp->d_name;
483         std::string file;
484         if (!android::base::ReadFileToString(file_name, &file)) continue;
485 
486         bool found = false;
487         for (const auto& line : android::base::Split(file, "\n")) {
488             log_time t(log_time::EPOCH);
489             char* ep = parseTime(t, line.c_str());
490             if (!ep || (*ep != ' ')) continue;
491             // determine the time precision of the logs (eg: msec or usec)
492             for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
493                 if (t.tv_nsec % (mod * 10)) {
494                     modulo.tv_nsec = mod;
495                     break;
496                 }
497             }
498             // We filter any times later than current as we may not have the
499             // year stored with each log entry. Also, since it is possible for
500             // entries to be recorded out of order (very rare) we select the
501             // maximum we find just in case.
502             if ((t < now) && (t > retval)) {
503                 retval = t;
504                 found = true;
505             }
506         }
507         // We count on the basename file to be the definitive end, so stop here.
508         if (!dp->d_name[len] && found) break;
509     }
510     if (retval == log_time::EPOCH) return retval;
511     // tail_time prints matching or higher, round up by the modulo to prevent
512     // a replay of the last entry we have just checked.
513     retval += modulo;
514     return retval;
515 }
516 
ReportErrorName(const std::string & name,bool allow_security,std::vector<std::string> * errors)517 void ReportErrorName(const std::string& name, bool allow_security,
518                      std::vector<std::string>* errors) {
519     if (allow_security || name != "security") {
520         errors->emplace_back(name);
521     }
522 }
523 
Run(int argc,char ** argv)524 int Logcat::Run(int argc, char** argv) {
525     bool hasSetLogFormat = false;
526     bool clearLog = false;
527     bool security_buffer_selected =
528             false;  // Do not report errors on the security buffer unless it is explicitly named.
529     bool getLogSize = false;
530     bool getPruneList = false;
531     bool printStatistics = false;
532     bool printDividers = false;
533     unsigned long setLogSize = 0;
534     const char* setPruneList = nullptr;
535     const char* setId = nullptr;
536     int mode = 0;
537     std::string forceFilters;
538     size_t tail_lines = 0;
539     log_time tail_time(log_time::EPOCH);
540     size_t pid = 0;
541     bool got_t = false;
542     unsigned id_mask = 0;
543     std::set<uid_t> uids;
544 
545     if (argc == 2 && !strcmp(argv[1], "--help")) {
546         show_help();
547         return EXIT_SUCCESS;
548     }
549 
550     // meant to catch comma-delimited values, but cast a wider
551     // net for stability dealing with possible mistaken inputs.
552     static const char delimiters[] = ",:; \t\n\r\f";
553 
554     optind = 0;
555     while (true) {
556         int option_index = 0;
557         // list of long-argument only strings for later comparison
558         static const char pid_str[] = "pid";
559         static const char debug_str[] = "debug";
560         static const char id_str[] = "id";
561         static const char wrap_str[] = "wrap";
562         static const char print_str[] = "print";
563         static const char uid_str[] = "uid";
564         // clang-format off
565         static const struct option long_options[] = {
566           { "binary",        no_argument,       nullptr, 'B' },
567           { "buffer",        required_argument, nullptr, 'b' },
568           { "buffer-size",   optional_argument, nullptr, 'g' },
569           { "clear",         no_argument,       nullptr, 'c' },
570           { debug_str,       no_argument,       nullptr, 0 },
571           { "dividers",      no_argument,       nullptr, 'D' },
572           { "file",          required_argument, nullptr, 'f' },
573           { "format",        required_argument, nullptr, 'v' },
574           // hidden and undocumented reserved alias for --regex
575           { "grep",          required_argument, nullptr, 'e' },
576           // hidden and undocumented reserved alias for --max-count
577           { "head",          required_argument, nullptr, 'm' },
578           { "help",          no_argument,       nullptr, 'h' },
579           { id_str,          required_argument, nullptr, 0 },
580           { "last",          no_argument,       nullptr, 'L' },
581           { "max-count",     required_argument, nullptr, 'm' },
582           { pid_str,         required_argument, nullptr, 0 },
583           { print_str,       no_argument,       nullptr, 0 },
584           { "prune",         optional_argument, nullptr, 'p' },
585           { "regex",         required_argument, nullptr, 'e' },
586           { "rotate-count",  required_argument, nullptr, 'n' },
587           { "rotate-kbytes", required_argument, nullptr, 'r' },
588           { "statistics",    no_argument,       nullptr, 'S' },
589           // hidden and undocumented reserved alias for -t
590           { "tail",          required_argument, nullptr, 't' },
591           { uid_str,         required_argument, nullptr, 0 },
592           // support, but ignore and do not document, the optional argument
593           { wrap_str,        optional_argument, nullptr, 0 },
594           { nullptr,         0,                 nullptr, 0 }
595         };
596         // clang-format on
597 
598         int c = getopt_long(argc, argv, ":cdDhLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", long_options,
599                             &option_index);
600         if (c == -1) break;
601 
602         switch (c) {
603             case 0:
604                 // only long options
605                 if (long_options[option_index].name == pid_str) {
606                     if (pid != 0) {
607                         error(EXIT_FAILURE, 0, "Only one --pid argument can be provided.");
608                     }
609 
610                     if (!ParseUint(optarg, &pid) || pid < 1) {
611                         error(EXIT_FAILURE, 0, "%s %s out of range.",
612                               long_options[option_index].name, optarg);
613                     }
614                     break;
615                 }
616                 if (long_options[option_index].name == wrap_str) {
617                     mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK;
618                     // ToDo: implement API that supports setting a wrap timeout
619                     size_t timeout = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
620                     if (optarg && (!ParseUint(optarg, &timeout) || timeout < 1)) {
621                         error(EXIT_FAILURE, 0, "%s %s out of range.",
622                               long_options[option_index].name, optarg);
623                     }
624                     if (timeout != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
625                         fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
626                                 long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
627                                 timeout);
628                     }
629                     break;
630                 }
631                 if (long_options[option_index].name == print_str) {
632                     print_it_anyways_ = true;
633                     break;
634                 }
635                 if (long_options[option_index].name == debug_str) {
636                     debug_ = true;
637                     break;
638                 }
639                 if (long_options[option_index].name == id_str) {
640                     setId = (optarg && optarg[0]) ? optarg : nullptr;
641                 }
642                 if (long_options[option_index].name == uid_str) {
643                     auto uid_strings = Split(optarg, delimiters);
644                     for (const auto& uid_string : uid_strings) {
645                         uid_t uid;
646                         if (!ParseUint(uid_string, &uid)) {
647                             error(EXIT_FAILURE, 0, "Unable to parse UID '%s'", uid_string.c_str());
648                         }
649                         uids.emplace(uid);
650                     }
651                     break;
652                 }
653                 break;
654 
655             case 's':
656                 // default to all silent
657                 android_log_addFilterRule(logformat_.get(), "*:s");
658                 break;
659 
660             case 'c':
661                 clearLog = true;
662                 break;
663 
664             case 'L':
665                 mode |= ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
666                 break;
667 
668             case 'd':
669                 mode |= ANDROID_LOG_NONBLOCK;
670                 break;
671 
672             case 't':
673                 got_t = true;
674                 mode |= ANDROID_LOG_NONBLOCK;
675                 FALLTHROUGH_INTENDED;
676             case 'T':
677                 if (strspn(optarg, "0123456789") != strlen(optarg)) {
678                     char* cp = parseTime(tail_time, optarg);
679                     if (!cp) {
680                         error(EXIT_FAILURE, 0, "-%c '%s' not in time format.", c, optarg);
681                     }
682                     if (*cp) {
683                         char ch = *cp;
684                         *cp = '\0';
685                         fprintf(stderr, "WARNING: -%c '%s' '%c%s' time truncated\n", c, optarg, ch,
686                                 cp + 1);
687                         *cp = ch;
688                     }
689                 } else {
690                     if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
691                         fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
692                         tail_lines = 1;
693                     }
694                 }
695                 break;
696 
697             case 'D':
698                 printDividers = true;
699                 break;
700 
701             case 'e':
702                 regex_.reset(new std::regex(optarg));
703                 break;
704 
705             case 'm': {
706                 if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
707                     error(EXIT_FAILURE, 0, "-%c '%s' isn't an integer greater than zero.", c,
708                           optarg);
709                 }
710             } break;
711 
712             case 'g':
713                 if (!optarg) {
714                     getLogSize = true;
715                     break;
716                 }
717                 FALLTHROUGH_INTENDED;
718 
719             case 'G': {
720                 if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
721                     error(EXIT_FAILURE, 0, "-G must be specified as <num><multiplier>.");
722                 }
723             } break;
724 
725             case 'p':
726                 if (!optarg) {
727                     getPruneList = true;
728                     break;
729                 }
730                 FALLTHROUGH_INTENDED;
731 
732             case 'P':
733                 setPruneList = optarg;
734                 break;
735 
736             case 'b':
737                 for (const auto& buffer : Split(optarg, delimiters)) {
738                     if (buffer == "default") {
739                         id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
740                     } else if (buffer == "all") {
741                         id_mask = -1;
742                     } else {
743                         log_id_t log_id = android_name_to_log_id(buffer.c_str());
744                         if (log_id >= LOG_ID_MAX) {
745                             error(EXIT_FAILURE, 0, "Unknown buffer '%s' listed for -b.",
746                                   buffer.c_str());
747                         }
748                         if (log_id == LOG_ID_SECURITY) {
749                             security_buffer_selected = true;
750                         }
751                         id_mask |= (1 << log_id);
752                     }
753                 }
754                 break;
755 
756             case 'B':
757                 print_binary_ = 1;
758                 break;
759 
760             case 'f':
761                 if ((tail_time == log_time::EPOCH) && !tail_lines) {
762                     tail_time = lastLogTime(optarg);
763                 }
764                 // redirect output to a file
765                 output_file_name_ = optarg;
766                 break;
767 
768             case 'r':
769                 if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
770                     error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -r.", optarg);
771                 }
772                 break;
773 
774             case 'n':
775                 if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
776                     error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -n.", optarg);
777                 }
778                 break;
779 
780             case 'v':
781                 if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
782                     show_format_help();
783                     return EXIT_SUCCESS;
784                 }
785                 for (const auto& arg : Split(optarg, delimiters)) {
786                     int err = SetLogFormat(arg.c_str());
787                     if (err < 0) {
788                         error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -v.", arg.c_str());
789                     }
790                     if (err) hasSetLogFormat = true;
791                 }
792                 break;
793 
794             case 'Q':
795 #define LOGCAT_FILTER "androidboot.logcat="
796 #define CONSOLE_PIPE_OPTION "androidboot.consolepipe="
797 #define CONSOLE_OPTION "androidboot.console="
798 #define QEMU_PROPERTY "ro.kernel.qemu"
799 #define QEMU_CMDLINE "qemu.cmdline"
800                 // This is a *hidden* option used to start a version of logcat
801                 // in an emulated device only.  It basically looks for
802                 // androidboot.logcat= on the kernel command line.  If
803                 // something is found, it extracts a log filter and uses it to
804                 // run the program. The logcat output will go to consolepipe if
805                 // androiboot.consolepipe (e.g. qemu_pipe) is given, otherwise,
806                 // it goes to androidboot.console (e.g. tty)
807                 {
808                     // if not in emulator, exit quietly
809                     if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) {
810                         return EXIT_SUCCESS;
811                     }
812 
813                     std::string cmdline = android::base::GetProperty(QEMU_CMDLINE, "");
814                     if (cmdline.empty()) {
815                         android::base::ReadFileToString("/proc/cmdline", &cmdline);
816                     }
817 
818                     const char* logcatFilter = strstr(cmdline.c_str(), LOGCAT_FILTER);
819                     // if nothing found or invalid filters, exit quietly
820                     if (!logcatFilter) {
821                         return EXIT_SUCCESS;
822                     }
823 
824                     const char* p = logcatFilter + strlen(LOGCAT_FILTER);
825                     const char* q = strpbrk(p, " \t\n\r");
826                     if (!q) q = p + strlen(p);
827                     forceFilters = std::string(p, q);
828 
829                     // redirect our output to the emulator console pipe or console
830                     const char* consolePipe =
831                         strstr(cmdline.c_str(), CONSOLE_PIPE_OPTION);
832                     const char* console =
833                         strstr(cmdline.c_str(), CONSOLE_OPTION);
834 
835                     if (consolePipe) {
836                         p = consolePipe + strlen(CONSOLE_PIPE_OPTION);
837                     } else if (console) {
838                         p = console + strlen(CONSOLE_OPTION);
839                     } else {
840                         return EXIT_FAILURE;
841                     }
842 
843                     q = strpbrk(p, " \t\n\r");
844                     int len = q ? q - p : strlen(p);
845                     std::string devname = "/dev/" + std::string(p, len);
846                     std::string pipePurpose("pipe:logcat");
847                     if (consolePipe) {
848                         // example: "qemu_pipe,pipe:logcat"
849                         // upon opening of /dev/qemu_pipe, the "pipe:logcat"
850                         // string with trailing '\0' should be written to the fd
851                         size_t pos = devname.find(',');
852                         if (pos != std::string::npos) {
853                             pipePurpose = devname.substr(pos + 1);
854                             devname = devname.substr(0, pos);
855                         }
856                     }
857 
858                     fprintf(stderr, "logcat using %s\n", devname.c_str());
859 
860                     int fd = open(devname.c_str(), O_WRONLY | O_CLOEXEC);
861                     if (fd < 0) {
862                         break;
863                     }
864 
865                     if (consolePipe) {
866                         // need the trailing '\0'
867                         if (!android::base::WriteFully(fd, pipePurpose.c_str(),
868                                                        pipePurpose.size() + 1)) {
869                             close(fd);
870                             return EXIT_FAILURE;
871                         }
872                     }
873                     // close output and error channels, replace with console
874                     dup2(fd, output_fd_.get());
875                     dup2(fd, STDERR_FILENO);
876                     close(fd);
877                 }
878                 break;
879 
880             case 'S':
881                 printStatistics = true;
882                 break;
883 
884             case ':':
885                 error(EXIT_FAILURE, 0, "Option '%s' needs an argument.", argv[optind - 1]);
886                 break;
887 
888             case 'h':
889                 show_help();
890                 show_format_help();
891                 return EXIT_SUCCESS;
892 
893             case '?':
894                 error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind - 1]);
895                 break;
896 
897             default:
898                 error(EXIT_FAILURE, 0, "Unknown getopt_long() result '%c'.", c);
899         }
900     }
901 
902     if (max_count_ && got_t) {
903         error(EXIT_FAILURE, 0, "Cannot use -m (--max-count) and -t together.");
904     }
905     if (print_it_anyways_ && (!regex_ || !max_count_)) {
906         // One day it would be nice if --print -v color and --regex <expr>
907         // could play with each other and show regex highlighted content.
908         fprintf(stderr,
909                 "WARNING: "
910                 "--print ignored, to be used in combination with\n"
911                 "         "
912                 "--regex <expr> and --max-count <N>\n");
913         print_it_anyways_ = false;
914     }
915 
916     // If no buffers are specified, default to using these buffers.
917     if (id_mask == 0) {
918         id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
919                   (1 << LOG_ID_KERNEL);
920     }
921 
922     if (log_rotate_size_kb_ != 0 && !output_file_name_) {
923         error(EXIT_FAILURE, 0, "-r requires -f as well.");
924     }
925 
926     if (setId != 0) {
927         if (!output_file_name_) {
928             error(EXIT_FAILURE, 0, "--id='%s' requires -f as well.", setId);
929         }
930 
931         std::string file_name = StringPrintf("%s.id", output_file_name_);
932         std::string file;
933         bool file_ok = android::base::ReadFileToString(file_name, &file);
934         android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
935                                          getuid(), getgid());
936         if (!file_ok || !file.compare(setId)) setId = nullptr;
937     }
938 
939     if (!hasSetLogFormat) {
940         const char* logFormat = getenv("ANDROID_PRINTF_LOG");
941 
942         if (!!logFormat) {
943             for (const auto& arg : Split(logFormat, delimiters)) {
944                 int err = SetLogFormat(arg.c_str());
945                 // environment should not cause crash of logcat
946                 if (err < 0) {
947                     fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
948                 }
949                 if (err > 0) hasSetLogFormat = true;
950             }
951         }
952         if (!hasSetLogFormat) {
953             SetLogFormat("threadtime");
954         }
955     }
956 
957     if (forceFilters.size()) {
958         int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
959         if (err < 0) {
960             error(EXIT_FAILURE, 0, "Invalid filter expression in logcat args.");
961         }
962     } else if (argc == optind) {
963         // Add from environment variable
964         const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
965 
966         if (!!env_tags_orig) {
967             int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
968 
969             if (err < 0) {
970                 error(EXIT_FAILURE, 0, "Invalid filter expression in ANDROID_LOG_TAGS.");
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 (output_file_name_) {
985             error(EXIT_FAILURE, 0, "-c is ambiguous with both -f and -L specified.");
986         }
987         if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
988             error(EXIT_FAILURE, 0, "-L is incompatible with -g/-G, -S, and -p/-P.");
989         }
990         if (clearLog) {
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 
1068             if (size < 0 || readable < 0) {
1069                 ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
1070             } else {
1071                 auto size_format = format_of_size(size);
1072                 auto readable_format = format_of_size(readable);
1073                 std::string str = android::base::StringPrintf(
1074                         "%s: ring buffer is %lu %sB (%lu %sB consumed),"
1075                         " max entry is %d B, max payload is %d B\n",
1076                         buffer_name, size_format.first, size_format.second, readable_format.first,
1077                         readable_format.second, (int)LOGGER_ENTRY_MAX_LEN,
1078                         (int)LOGGER_ENTRY_MAX_PAYLOAD);
1079                 TEMP_FAILURE_RETRY(write(output_fd_.get(), str.data(), str.length()));
1080             }
1081         }
1082     }
1083 
1084     // report any errors in the above loop and exit
1085     if (!open_device_failures.empty()) {
1086         error(EXIT_FAILURE, 0, "Unable to open log device%s '%s'.",
1087               open_device_failures.size() > 1 ? "s" : "", Join(open_device_failures, ",").c_str());
1088     }
1089     if (!clear_failures.empty()) {
1090         error(EXIT_FAILURE, 0, "failed to clear the '%s' log%s.", Join(clear_failures, ",").c_str(),
1091               clear_failures.size() > 1 ? "s" : "");
1092     }
1093     if (!set_size_failures.empty()) {
1094         error(EXIT_FAILURE, 0, "failed to set the '%s' log size%s.",
1095               Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
1096     }
1097     if (!get_size_failures.empty()) {
1098         error(EXIT_FAILURE, 0, "failed to get the readable '%s' log size%s.",
1099               Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
1100     }
1101 
1102     if (setPruneList) {
1103         size_t len = strlen(setPruneList);
1104         if (android_logger_set_prune_list(logger_list.get(), setPruneList, len)) {
1105             error(EXIT_FAILURE, 0, "Failed to set the prune list.");
1106         }
1107         return EXIT_SUCCESS;
1108     }
1109 
1110     if (printStatistics || getPruneList) {
1111         std::string buf(8192, '\0');
1112         size_t ret_length = 0;
1113         int retry = 32;
1114 
1115         for (; retry >= 0; --retry) {
1116             if (getPruneList) {
1117                 android_logger_get_prune_list(logger_list.get(), buf.data(), buf.size());
1118             } else {
1119                 android_logger_get_statistics(logger_list.get(), buf.data(), buf.size());
1120             }
1121 
1122             ret_length = atol(buf.c_str());
1123             if (ret_length < 3) {
1124                 error(EXIT_FAILURE, 0, "Failed to read data.");
1125             }
1126 
1127             if (ret_length < buf.size()) {
1128                 break;
1129             }
1130 
1131             buf.resize(ret_length + 1);
1132         }
1133 
1134         if (retry < 0) {
1135             error(EXIT_FAILURE, 0, "Failed to read data.");
1136         }
1137 
1138         buf.resize(ret_length);
1139         if (buf.back() == '\f') {
1140             buf.pop_back();
1141         }
1142 
1143         // Remove the byte count prefix
1144         const char* cp = buf.c_str();
1145         while (isdigit(*cp)) ++cp;
1146         if (*cp == '\n') ++cp;
1147 
1148         size_t len = strlen(cp);
1149         TEMP_FAILURE_RETRY(write(output_fd_.get(), cp, len));
1150         return EXIT_SUCCESS;
1151     }
1152 
1153     if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
1154 
1155     SetupOutputAndSchedulingPolicy(!(mode & ANDROID_LOG_NONBLOCK));
1156 
1157     while (!max_count_ || print_count_ < max_count_) {
1158         struct log_msg log_msg;
1159         int ret = android_logger_list_read(logger_list.get(), &log_msg);
1160         if (!ret) {
1161             error(EXIT_FAILURE, 0, R"init(Unexpected EOF!
1162 
1163 This means that either the device shut down, logd crashed, or this instance of logcat was unable to read log
1164 messages as quickly as they were being produced.
1165 
1166 If you have enabled significant logging, look into using the -G option to increase log buffer sizes.)init");
1167         }
1168 
1169         if (ret < 0) {
1170             if (ret == -EAGAIN) break;
1171 
1172             if (ret == -EIO) {
1173                 error(EXIT_FAILURE, 0, "Unexpected EOF!");
1174             }
1175             if (ret == -EINVAL) {
1176                 error(EXIT_FAILURE, 0, "Unexpected length.");
1177             }
1178             error(EXIT_FAILURE, errno, "Logcat read failure");
1179         }
1180 
1181         if (log_msg.id() > LOG_ID_MAX) {
1182             error(EXIT_FAILURE, 0, "Unexpected log id (%d) over LOG_ID_MAX (%d).", log_msg.id(),
1183                   LOG_ID_MAX);
1184         }
1185 
1186         if (!uids.empty() && uids.count(log_msg.entry.uid) == 0) {
1187             continue;
1188         }
1189 
1190         PrintDividers(log_msg.id(), printDividers);
1191 
1192         if (print_binary_) {
1193             TEMP_FAILURE_RETRY(write(output_fd_.get(), &log_msg, log_msg.len()));
1194         } else {
1195             ProcessBuffer(&log_msg);
1196         }
1197     }
1198     return EXIT_SUCCESS;
1199 }
1200 
main(int argc,char ** argv)1201 int main(int argc, char** argv) {
1202     Logcat logcat;
1203     return logcat.Run(argc, argv);
1204 }
1205