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