• 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     printf(R"logcat(
276   Usage: logcat [OPTION]... [FILTERSPEC]...
277 
278   General options:
279 
280   -b BUFFER, --buffer=BUFFER
281       Request alternate ring buffer(s). Options are:
282           main system radio events crash default all
283       Additionally, 'kernel' for userdebug and eng builds, and 'security' for
284       Device Owner installations.
285       Multiple -b parameters or comma separated list of buffers are
286       allowed. Buffers are interleaved.
287       Default is "main,system,crash,kernel".
288   -c, --clear
289       Clear (flush) the entire log and exit. With -f, clear the specified file
290       and its related rotated log files instead. With -L, clear pstore instead.
291   -d            Dump the log and then exit (don't block).
292   -L, --last    Dump logs from prior to last reboot from pstore.
293   --pid=PID     Only print logs from the given pid.
294   --wrap
295       Sleep for 2 hours or until buffer about to wrap (whichever comes first).
296       Improves efficiency of polling by providing an about-to-wrap wakeup.
297 
298   Formatting:
299 
300   -v, --format=FORMAT         Sets log print format. See FORMAT below.
301   -D, --dividers              Print dividers between each log buffer.
302   -B, --binary                Output the log in binary.
303 
304   Output files:
305 
306   -f, --file=FILE             Log to FILE instead of stdout.
307   -r, --rotate-kbytes=N       Rotate log every N KiB. Requires -f.
308   -n, --rotate-count=N        Sets max number of rotated logs, default 4.
309   --id=<id>
310       Clears the associated files if the signature <id> for logging to file
311       changes.
312 
313   Logd control:
314 
315   These options send a control message to the logd daemon on device, print its
316   return message if applicable, then exit. They are incompatible with -L
317   because these attributes do not apply to pstore.
318 
319   -g, --buffer-size
320       Get size of the ring buffers within logd.
321   -G, --buffer-size=SIZE
322       Set size of a ring buffer in logd. May suffix with K or M.
323       This can individually control each buffer's size with -b.
324   -p, --prune
325       Get prune rules. Each rule is specified as UID, UID/PID or /PID. A
326       '~' prefix indicates that elements matching the rule should be pruned
327       with higher priority otherwise they're pruned with lower priority. All
328       other pruning activity is oldest first. Special case ~! represents an
329       automatic pruning for the noisiest UID as determined by the current
330       statistics. Special case ~1000/! represents pruning of the worst PID
331       within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
332   -P, --prune='LIST ...'
333       Set prune rules, using same format as listed above. Must be quoted.
334   -S, --statistics
335       Output statistics. With --pid provides pid-specific stats.
336 
337   Filtering:
338 
339   -s                   Set default filter to silent (like filterspec '*:S').
340   -e, --regex=EXPR     Only print lines matching ECMAScript regex.
341   -m, --max-count=N    Exit after printing <count> lines.
342   --print              With --regex and --max-count, prints all messages
343                        even if they do not match the regex, but exits after
344                        printing max-count matching lines.
345   -t N                 Print most recent <count> lines (implies -d).
346   -T N                 Print most recent <count> lines (does not imply -d).
347   -t TIME              Print lines since specified time (implies -d).
348   -T TIME              Print lines since specified time (not imply -d).
349                        Time format is 'MM-DD hh:mm:ss.mmm...',
350                        'YYYY-MM-DD hh:mm:ss.mmm...', or 'sssss.mmm...'.
351   --uid=UIDS
352       Only display log messages from UIDs in the comma-separated list UIDS.
353       UIDs must be numeric because no name lookup is performed.
354       Note that only root/log/system users can view logs from other users.
355 
356   FILTERSPEC:
357 
358   Filter specifications are a series of
359 
360     <tag>[:priority]
361 
362   where <tag> is a log component tag (or * for all) and priority is:
363 
364     V    Verbose (default for <tag>)
365     D    Debug (default for '*')
366     I    Info
367     W    Warn
368     E    Error
369     F    Fatal
370     S    Silent (suppress all output)
371 
372   '*' by itself means '*:D' and <tag> by itself means <tag>:V.
373   If no '*' filterspec or -s on command line, all filter defaults to '*:V'.
374   '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.
375 
376   If not specified on the command line, FILTERSPEC is $ANDROID_LOG_TAGS.
377 
378   FORMAT:
379 
380   Formats are a comma-separated sequence of verbs and adverbs.
381 
382   Single format verbs:
383 
384     brief      Show priority, tag, and PID of the process issuing the message.
385     long       Show all metadata fields and separate messages with blank lines.
386     process    Show PID only.
387     raw        Show the raw log message with no other metadata fields.
388     tag        Show the priority and tag only.
389     thread     Show priority, PID, and TID of the thread issuing the message.
390     threadtime Show the date, invocation time, priority, tag, PID, and TID of
391                the thread issuing the message. (This is the default.)
392     time       Show the date, invocation time, priority, tag, and PID of the
393                process issuing the message.
394 
395   Adverb modifiers can be used in combination:
396 
397     color       Show each priority with a different color.
398     descriptive Show event descriptions from event-log-tags database.
399     epoch       Show time as seconds since 1970-01-01 (Unix epoch).
400     monotonic   Show time as CPU seconds since boot.
401     printable   Ensure that any binary logging content is escaped.
402     uid         Show UID or Android ID of logged process (if permitted).
403     usec        Show time with microsecond precision.
404     UTC         Show time as UTC.
405     year        Add the year to the displayed time.
406     zone        Add the local timezone to the displayed time.
407     \"<ZONE>\"  Print using this named timezone (experimental).
408 
409   If not specified with -v on command line, FORMAT is $ANDROID_PRINTF_LOG or
410   defaults to "threadtime".
411 )logcat");
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(CLOCK_REALTIME);
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     unsigned long setLogSize = 0;
527     const char* setPruneList = nullptr;
528     const char* setId = nullptr;
529     int mode = 0;
530     std::string forceFilters;
531     size_t tail_lines = 0;
532     log_time tail_time(log_time::EPOCH);
533     size_t pid = 0;
534     bool got_t = false;
535     unsigned id_mask = 0;
536     std::set<uid_t> uids;
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         static const char uid_str[] = "uid";
557         // clang-format off
558         static const struct option long_options[] = {
559           { "binary",        no_argument,       nullptr, 'B' },
560           { "buffer",        required_argument, nullptr, 'b' },
561           { "buffer-size",   optional_argument, nullptr, 'g' },
562           { "clear",         no_argument,       nullptr, 'c' },
563           { debug_str,       no_argument,       nullptr, 0 },
564           { "dividers",      no_argument,       nullptr, 'D' },
565           { "file",          required_argument, nullptr, 'f' },
566           { "format",        required_argument, nullptr, 'v' },
567           // hidden and undocumented reserved alias for --regex
568           { "grep",          required_argument, nullptr, 'e' },
569           // hidden and undocumented reserved alias for --max-count
570           { "head",          required_argument, nullptr, 'm' },
571           { "help",          no_argument,       nullptr, 'h' },
572           { id_str,          required_argument, nullptr, 0 },
573           { "last",          no_argument,       nullptr, 'L' },
574           { "max-count",     required_argument, nullptr, 'm' },
575           { pid_str,         required_argument, nullptr, 0 },
576           { print_str,       no_argument,       nullptr, 0 },
577           { "prune",         optional_argument, nullptr, 'p' },
578           { "regex",         required_argument, nullptr, 'e' },
579           { "rotate-count",  required_argument, nullptr, 'n' },
580           { "rotate-kbytes", required_argument, nullptr, 'r' },
581           { "statistics",    no_argument,       nullptr, 'S' },
582           // hidden and undocumented reserved alias for -t
583           { "tail",          required_argument, nullptr, 't' },
584           { uid_str,         required_argument, nullptr, 0 },
585           // support, but ignore and do not document, the optional argument
586           { wrap_str,        optional_argument, nullptr, 0 },
587           { nullptr,         0,                 nullptr, 0 }
588         };
589         // clang-format on
590 
591         int c = getopt_long(argc, argv, ":cdDhLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", long_options,
592                             &option_index);
593         if (c == -1) break;
594 
595         switch (c) {
596             case 0:
597                 // only long options
598                 if (long_options[option_index].name == pid_str) {
599                     if (pid != 0) {
600                         error(EXIT_FAILURE, 0, "Only one --pid argument can be provided.");
601                     }
602 
603                     if (!ParseUint(optarg, &pid) || pid < 1) {
604                         error(EXIT_FAILURE, 0, "%s %s out of range.",
605                               long_options[option_index].name, optarg);
606                     }
607                     break;
608                 }
609                 if (long_options[option_index].name == wrap_str) {
610                     mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK;
611                     // ToDo: implement API that supports setting a wrap timeout
612                     size_t timeout = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
613                     if (optarg && (!ParseUint(optarg, &timeout) || timeout < 1)) {
614                         error(EXIT_FAILURE, 0, "%s %s out of range.",
615                               long_options[option_index].name, optarg);
616                     }
617                     if (timeout != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
618                         fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
619                                 long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
620                                 timeout);
621                     }
622                     break;
623                 }
624                 if (long_options[option_index].name == print_str) {
625                     print_it_anyway_ = true;
626                     break;
627                 }
628                 if (long_options[option_index].name == debug_str) {
629                     debug_ = true;
630                     break;
631                 }
632                 if (long_options[option_index].name == id_str) {
633                     setId = (optarg && optarg[0]) ? optarg : nullptr;
634                 }
635                 if (long_options[option_index].name == uid_str) {
636                     auto uid_strings = Split(optarg, delimiters);
637                     for (const auto& uid_string : uid_strings) {
638                         uid_t uid;
639                         if (!ParseUint(uid_string, &uid)) {
640                             error(EXIT_FAILURE, 0, "Unable to parse UID '%s'", uid_string.c_str());
641                         }
642                         uids.emplace(uid);
643                     }
644                     break;
645                 }
646                 break;
647 
648             case 's':
649                 // default to all silent
650                 android_log_addFilterRule(logformat_.get(), "*:s");
651                 break;
652 
653             case 'c':
654                 clearLog = true;
655                 break;
656 
657             case 'L':
658                 mode |= ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
659                 break;
660 
661             case 'd':
662                 mode |= ANDROID_LOG_NONBLOCK;
663                 break;
664 
665             case 't':
666                 got_t = true;
667                 mode |= ANDROID_LOG_NONBLOCK;
668                 FALLTHROUGH_INTENDED;
669             case 'T':
670                 if (strspn(optarg, "0123456789") != strlen(optarg)) {
671                     char* cp = parseTime(tail_time, optarg);
672                     if (!cp) {
673                         error(EXIT_FAILURE, 0, "-%c '%s' not in time format.", c, optarg);
674                     }
675                     if (*cp) {
676                         char ch = *cp;
677                         *cp = '\0';
678                         fprintf(stderr, "WARNING: -%c '%s' '%c%s' time truncated\n", c, optarg, ch,
679                                 cp + 1);
680                         *cp = ch;
681                     }
682                 } else {
683                     if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
684                         fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
685                         tail_lines = 1;
686                     }
687                 }
688                 break;
689 
690             case 'D':
691                 print_dividers_ = true;
692                 break;
693 
694             case 'e':
695                 regex_.reset(new std::regex(optarg));
696                 break;
697 
698             case 'm': {
699                 if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
700                     error(EXIT_FAILURE, 0, "-%c '%s' isn't an integer greater than zero.", c,
701                           optarg);
702                 }
703             } break;
704 
705             case 'g':
706                 if (!optarg) {
707                     getLogSize = true;
708                     break;
709                 }
710                 FALLTHROUGH_INTENDED;
711 
712             case 'G': {
713                 if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
714                     error(EXIT_FAILURE, 0, "-G must be specified as <num><multiplier>.");
715                 }
716             } break;
717 
718             case 'p':
719                 if (!optarg) {
720                     getPruneList = true;
721                     break;
722                 }
723                 FALLTHROUGH_INTENDED;
724 
725             case 'P':
726                 setPruneList = optarg;
727                 break;
728 
729             case 'b':
730                 for (const auto& buffer : Split(optarg, delimiters)) {
731                     if (buffer == "default") {
732                         id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
733                     } else if (buffer == "all") {
734                         id_mask = -1;
735                     } else {
736                         log_id_t log_id = android_name_to_log_id(buffer.c_str());
737                         if (log_id >= LOG_ID_MAX) {
738                             error(EXIT_FAILURE, 0, "Unknown buffer '%s' listed for -b.",
739                                   buffer.c_str());
740                         }
741                         if (log_id == LOG_ID_SECURITY) {
742                             security_buffer_selected = true;
743                         }
744                         id_mask |= (1 << log_id);
745                     }
746                 }
747                 break;
748 
749             case 'B':
750                 print_binary_ = 1;
751                 break;
752 
753             case 'f':
754                 if ((tail_time == log_time::EPOCH) && !tail_lines) {
755                     tail_time = lastLogTime(optarg);
756                 }
757                 // redirect output to a file
758                 output_file_name_ = optarg;
759                 break;
760 
761             case 'r':
762                 if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
763                     error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -r.", optarg);
764                 }
765                 break;
766 
767             case 'n':
768                 if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
769                     error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -n.", optarg);
770                 }
771                 break;
772 
773             case 'v':
774                 for (const auto& arg : Split(optarg, delimiters)) {
775                     int err = SetLogFormat(arg.c_str());
776                     if (err < 0) {
777                         error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -v.", arg.c_str());
778                     }
779                     if (err) hasSetLogFormat = true;
780                 }
781                 break;
782 
783             case 'S':
784                 printStatistics = true;
785                 break;
786 
787             case ':':
788                 error(EXIT_FAILURE, 0, "Option '%s' needs an argument.", argv[optind - 1]);
789                 break;
790 
791             case 'h':
792                 show_help();
793                 return EXIT_SUCCESS;
794 
795             case '?':
796                 error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind]);
797                 break;
798 
799             default:
800                 error(EXIT_FAILURE, 0, "Unknown getopt_long() result '%c'.", c);
801         }
802     }
803 
804     if (max_count_ && got_t) {
805         error(EXIT_FAILURE, 0, "Cannot use -m (--max-count) and -t together.");
806     }
807     if (print_it_anyway_ && (!regex_ || !max_count_)) {
808         // One day it would be nice if --print -v color and --regex <expr>
809         // could play with each other and show regex highlighted content.
810         fprintf(stderr,
811                 "WARNING: "
812                 "--print ignored, to be used in combination with\n"
813                 "         "
814                 "--regex <expr> and --max-count <N>\n");
815         print_it_anyway_ = false;
816     }
817 
818     // If no buffers are specified, default to using these buffers.
819     if (id_mask == 0) {
820         id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
821                   (1 << LOG_ID_KERNEL);
822     }
823 
824     if (log_rotate_size_kb_ != 0 && !output_file_name_) {
825         error(EXIT_FAILURE, 0, "-r requires -f as well.");
826     }
827 
828     if (setId != 0) {
829         if (!output_file_name_) {
830             error(EXIT_FAILURE, 0, "--id='%s' requires -f as well.", setId);
831         }
832 
833         std::string file_name = StringPrintf("%s.id", output_file_name_);
834         std::string file;
835         bool file_ok = android::base::ReadFileToString(file_name, &file);
836         android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
837                                          getuid(), getgid());
838         if (!file_ok || !file.compare(setId)) setId = nullptr;
839     }
840 
841     if (!hasSetLogFormat) {
842         const char* logFormat = getenv("ANDROID_PRINTF_LOG");
843 
844         if (!!logFormat) {
845             for (const auto& arg : Split(logFormat, delimiters)) {
846                 int err = SetLogFormat(arg.c_str());
847                 // environment should not cause crash of logcat
848                 if (err < 0) {
849                     fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
850                 }
851                 if (err > 0) hasSetLogFormat = true;
852             }
853         }
854         if (!hasSetLogFormat) {
855             SetLogFormat("threadtime");
856         }
857     }
858 
859     if (forceFilters.size()) {
860         int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
861         if (err < 0) {
862             error(EXIT_FAILURE, 0, "Invalid filter expression in logcat args.");
863         }
864     } else if (argc == optind) {
865         // Add from environment variable
866         const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
867 
868         if (!!env_tags_orig) {
869             int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
870 
871             if (err < 0) {
872                 error(EXIT_FAILURE, 0, "Invalid filter expression in ANDROID_LOG_TAGS.");
873             }
874         }
875     } else {
876         // Add from commandline
877         for (int i = optind ; i < argc ; i++) {
878             int err = android_log_addFilterString(logformat_.get(), argv[i]);
879             if (err < 0) {
880                 error(EXIT_FAILURE, 0, "Invalid filter expression '%s'.", argv[i]);
881             }
882         }
883     }
884 
885     if (mode & ANDROID_LOG_PSTORE) {
886         if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
887             error(EXIT_FAILURE, 0, "-L is incompatible with -g/-G, -S, and -p/-P.");
888         }
889         if (clearLog) {
890             if (output_file_name_) {
891                 error(EXIT_FAILURE, 0, "-c is ambiguous with both -f and -L specified.");
892             }
893             unlink("/sys/fs/pstore/pmsg-ramoops-0");
894             return EXIT_SUCCESS;
895         }
896     }
897 
898     if (output_file_name_) {
899         if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
900             error(EXIT_FAILURE, 0, "-f is incompatible with -g/-G, -S, and -p/-P.");
901         }
902 
903         if (clearLog || setId) {
904             int max_rotation_count_digits =
905                     max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
906 
907             for (int i = max_rotated_logs_; i >= 0; --i) {
908                 std::string file;
909 
910                 if (!i) {
911                     file = output_file_name_;
912                 } else {
913                     file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
914                 }
915 
916                 int err = unlink(file.c_str());
917 
918                 if (err < 0 && errno != ENOENT) {
919                     fprintf(stderr, "failed to delete log file '%s': %s\n", file.c_str(),
920                             strerror(errno));
921                 }
922             }
923         }
924 
925         if (clearLog) {
926             return EXIT_SUCCESS;
927         }
928     }
929 
930     std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
931             nullptr, &android_logger_list_free};
932     if (tail_time != log_time::EPOCH) {
933         logger_list.reset(android_logger_list_alloc_time(mode, tail_time, pid));
934     } else {
935         logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));
936     }
937     // We have three orthogonal actions below to clear, set log size and
938     // get log size. All sharing the same iteration loop.
939     std::vector<std::string> open_device_failures;
940     std::vector<std::string> clear_failures;
941     std::vector<std::string> set_size_failures;
942     std::vector<std::string> get_size_failures;
943 
944     for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
945         if (!(id_mask & (1 << i))) continue;
946         const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
947 
948         auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
949         if (logger == nullptr) {
950             ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
951             continue;
952         }
953 
954         if (clearLog) {
955             if (android_logger_clear(logger)) {
956                 ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
957             }
958         }
959 
960         if (setLogSize) {
961             if (android_logger_set_log_size(logger, setLogSize)) {
962                 ReportErrorName(buffer_name, security_buffer_selected, &set_size_failures);
963             }
964         }
965 
966         if (getLogSize) {
967             long size = android_logger_get_log_size(logger);
968             long readable = android_logger_get_log_readable_size(logger);
969             long consumed = android_logger_get_log_consumed_size(logger);
970 
971             if (size < 0 || readable < 0) {
972                 ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
973             } else {
974                 auto size_format = format_of_size(size);
975                 auto readable_format = format_of_size(readable);
976                 auto consumed_format = format_of_size(consumed);
977                 std::string str = android::base::StringPrintf(
978                         "%s: ring buffer is %lu %sB (%lu %sB consumed, %lu %sB readable),"
979                         " max entry is %d B, max payload is %d B\n",
980                         buffer_name, size_format.first, size_format.second, consumed_format.first,
981                         consumed_format.second, readable_format.first, readable_format.second,
982                         (int)LOGGER_ENTRY_MAX_LEN, (int)LOGGER_ENTRY_MAX_PAYLOAD);
983                 WriteFully(str.data(), str.length());
984             }
985         }
986     }
987 
988     // report any errors in the above loop and exit
989     if (!open_device_failures.empty()) {
990         error(EXIT_FAILURE, 0, "Unable to open log device%s '%s'.",
991               open_device_failures.size() > 1 ? "s" : "", Join(open_device_failures, ",").c_str());
992     }
993     if (!clear_failures.empty()) {
994         error(EXIT_FAILURE, 0, "failed to clear the '%s' log%s.", Join(clear_failures, ",").c_str(),
995               clear_failures.size() > 1 ? "s" : "");
996     }
997     if (!set_size_failures.empty()) {
998         error(EXIT_FAILURE, 0, "failed to set the '%s' log size%s.",
999               Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
1000     }
1001     if (!get_size_failures.empty()) {
1002         error(EXIT_FAILURE, 0, "failed to get the readable '%s' log size%s.",
1003               Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
1004     }
1005 
1006     if (setPruneList) {
1007         size_t len = strlen(setPruneList);
1008         if (android_logger_set_prune_list(logger_list.get(), setPruneList, len)) {
1009             error(EXIT_FAILURE, 0, "Failed to set the prune list.");
1010         }
1011         return EXIT_SUCCESS;
1012     }
1013 
1014     if (printStatistics || getPruneList) {
1015         std::string buf(8192, '\0');
1016         size_t ret_length = 0;
1017         int retry = 32;
1018 
1019         for (; retry >= 0; --retry) {
1020             if (getPruneList) {
1021                 android_logger_get_prune_list(logger_list.get(), buf.data(), buf.size());
1022             } else {
1023                 android_logger_get_statistics(logger_list.get(), buf.data(), buf.size());
1024             }
1025 
1026             ret_length = atol(buf.c_str());
1027             if (ret_length < 3) {
1028                 error(EXIT_FAILURE, 0, "Failed to read data.");
1029             }
1030 
1031             if (ret_length < buf.size()) {
1032                 break;
1033             }
1034 
1035             buf.resize(ret_length + 1);
1036         }
1037 
1038         if (retry < 0) {
1039             error(EXIT_FAILURE, 0, "Failed to read data.");
1040         }
1041 
1042         buf.resize(ret_length);
1043         if (buf.back() == '\f') {
1044             buf.pop_back();
1045         }
1046 
1047         // Remove the byte count prefix
1048         const char* cp = buf.c_str();
1049         while (isdigit(*cp)) ++cp;
1050         if (*cp == '\n') ++cp;
1051 
1052         WriteFully(cp, strlen(cp));
1053         return EXIT_SUCCESS;
1054     }
1055 
1056     if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
1057 
1058     bool blocking = !(mode & ANDROID_LOG_NONBLOCK);
1059     SetupOutputAndSchedulingPolicy(blocking);
1060 
1061     if (!WaitForProperty("logd.ready", "true", std::chrono::seconds(1))) {
1062         error(EXIT_FAILURE, 0, "Failed to wait for logd.ready to become true. logd not running?");
1063     }
1064 
1065     while (!max_count_ || print_count_ < max_count_) {
1066         struct log_msg log_msg;
1067         int ret = android_logger_list_read(logger_list.get(), &log_msg);
1068         if (!ret) {
1069             error(EXIT_FAILURE, 0, R"init(Unexpected EOF!
1070 
1071 This means that either the device shut down, logd crashed, or this instance of logcat was unable to read log
1072 messages as quickly as they were being produced.
1073 
1074 If you have enabled significant logging, look into using the -G option to increase log buffer sizes.)init");
1075         }
1076 
1077         if (ret < 0) {
1078             if (ret == -EAGAIN) break;
1079 
1080             if (ret == -EIO) {
1081                 error(EXIT_FAILURE, 0, "Unexpected EOF!");
1082             }
1083             if (ret == -EINVAL) {
1084                 error(EXIT_FAILURE, 0, "Unexpected length.");
1085             }
1086             error(EXIT_FAILURE, errno, "Logcat read failure");
1087         }
1088 
1089         if (log_msg.id() > LOG_ID_MAX) {
1090             error(EXIT_FAILURE, 0, "Unexpected log id (%d) over LOG_ID_MAX (%d).", log_msg.id(),
1091                   LOG_ID_MAX);
1092         }
1093 
1094         if (!uids.empty() && uids.count(log_msg.entry.uid) == 0) {
1095             continue;
1096         }
1097 
1098         if (print_binary_) {
1099             WriteFully(&log_msg, log_msg.len());
1100         } else {
1101             ProcessBuffer(&log_msg);
1102         }
1103         if (blocking && output_file_ == stdout) fflush(stdout);
1104     }
1105     return EXIT_SUCCESS;
1106 }
1107 
main(int argc,char ** argv)1108 int main(int argc, char** argv) {
1109     Logcat logcat;
1110     return logcat.Run(argc, argv);
1111 }
1112