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