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