blob: c0e11d3d189443ad3c5cee826114aa9f36fce084 [file] [log] [blame]
Mark Salyzynd8b454f2017-02-10 13:09:07 -08001/*
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08002 * Copyright (C) 2006-2017 The Android Open Source Project
Mark Salyzynd8b454f2017-02-10 13:09:07 -08003 *
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 */
The Android Open Source Project190995d2009-03-03 19:32:55 -080016
Mark Salyzyn12af9652013-12-13 11:10:11 -080017#include <ctype.h>
Mark Salyzyn3fa657e2015-05-27 07:39:56 -070018#include <dirent.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080019#include <errno.h>
20#include <fcntl.h>
Elliott Hughes442d8582018-06-15 15:16:20 -070021#include <getopt.h>
Aristidis Papaioannouf7cc6622014-10-16 22:19:55 -070022#include <math.h>
Mark Salyzyn38fc72c2015-06-02 07:57:16 -070023#include <sched.h>
Mark Salyzyn38fc72c2015-06-02 07:57:16 -070024#include <stdarg.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080025#include <stdio.h>
26#include <stdlib.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080027#include <string.h>
Traian Schiau9f978602015-04-10 15:51:39 +030028#include <sys/cdefs.h>
Jaegeuk Kim64352f22019-07-04 18:09:38 -070029#include <sys/ioctl.h>
Riley Andrews53fe1b02015-06-08 23:36:34 -070030#include <sys/resource.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080031#include <sys/stat.h>
Mark Salyzyn3fa657e2015-05-27 07:39:56 -070032#include <sys/types.h>
Mark Salyzyn38fc72c2015-06-02 07:57:16 -070033#include <time.h>
34#include <unistd.h>
Mark Salyzyn12af9652013-12-13 11:10:11 -080035
Mark Salyzyn3fa657e2015-05-27 07:39:56 -070036#include <memory>
Elliott Hughesaccc1012019-08-08 08:53:59 -070037#include <regex>
Mark Salyzyn3fa657e2015-05-27 07:39:56 -070038#include <string>
Wei Wang8b584172018-09-05 11:05:57 -070039#include <utility>
Mark Salyzyna511fef2017-02-10 13:09:07 -080040#include <vector>
Mark Salyzyn3fa657e2015-05-27 07:39:56 -070041
Elliott Hughes0a7adf02015-12-04 22:00:26 -080042#include <android-base/file.h>
Tom Cherryb1cf4282019-10-24 17:35:26 -070043#include <android-base/macros.h>
Tom Cherryfb1373a2019-10-29 07:05:24 -070044#include <android-base/parseint.h>
bohu25889532017-02-21 14:31:19 -080045#include <android-base/properties.h>
Mark Salyzyn2a1233e2016-08-03 14:20:41 -070046#include <android-base/stringprintf.h>
Elliott Hughes0a7adf02015-12-04 22:00:26 -080047#include <android-base/strings.h>
Tom Cherryb1cf4282019-10-24 17:35:26 -070048#include <android-base/unique_fd.h>
Tom Cherryfb1373a2019-10-29 07:05:24 -070049#include <android/log.h>
Mark Salyzyn38fc72c2015-06-02 07:57:16 -070050#include <log/event_tag_map.h>
Tom Cherryfb1373a2019-10-29 07:05:24 -070051#include <log/log_id.h>
Colin Crosse355ded2013-07-23 16:59:20 -070052#include <log/logprint.h>
Mark Salyzyn8b8bfd22016-09-30 13:30:33 -070053#include <private/android_logger.h>
Suren Baghdasaryan3e671a52019-01-25 05:32:52 +000054#include <processgroup/sched_policy.h>
Elliott Hughes411f8632016-02-17 11:58:01 -080055#include <system/thread_defs.h>
The Android Open Source Project190995d2009-03-03 19:32:55 -080056
The Android Open Source Project190995d2009-03-03 19:32:55 -080057#define DEFAULT_MAX_ROTATED_LOGS 4
58
Tom Cherryfb1373a2019-10-29 07:05:24 -070059using android::base::Join;
60using android::base::ParseByteCount;
61using android::base::ParseUint;
62using android::base::Split;
Tom Cherryb1cf4282019-10-24 17:35:26 -070063using android::base::StringPrintf;
64
Tom Cherryb1cf4282019-10-24 17:35:26 -070065class Logcat {
66 public:
Tom Cherryb1cf4282019-10-24 17:35:26 -070067 int Run(int argc, char** argv);
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -080068
Tom Cherryb1cf4282019-10-24 17:35:26 -070069 private:
70 void RotateLogs();
Tom Cherryfb1373a2019-10-29 07:05:24 -070071 void ProcessBuffer(struct log_msg* buf);
72 void PrintDividers(log_id_t log_id, bool print_dividers);
Tom Cherryb1cf4282019-10-24 17:35:26 -070073 void SetupOutputAndSchedulingPolicy(bool blocking);
74 int SetLogFormat(const char* format_string);
75
Tom Cherryfb1373a2019-10-29 07:05:24 -070076 // Used for all options
Tom Cherryb1cf4282019-10-24 17:35:26 -070077 android::base::unique_fd output_fd_{dup(STDOUT_FILENO)};
78 std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
79 android_log_format_new(), &android_log_format_free};
Tom Cherryfb1373a2019-10-29 07:05:24 -070080
81 // For logging to a file and log rotation
Tom Cherryb1cf4282019-10-24 17:35:26 -070082 const char* output_file_name_ = nullptr;
Tom Cherryfb1373a2019-10-29 07:05:24 -070083 size_t log_rotate_size_kb_ = 0; // 0 means "no log rotation"
84 size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
Tom Cherryb1cf4282019-10-24 17:35:26 -070085 size_t out_byte_count_ = 0;
Tom Cherryfb1373a2019-10-29 07:05:24 -070086
87 // For binary log buffers
Tom Cherryb1cf4282019-10-24 17:35:26 -070088 int print_binary_ = 0;
Tom Cherryb1cf4282019-10-24 17:35:26 -070089 std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
90 nullptr, &android_closeEventTagMap};
Tom Cherryb1cf4282019-10-24 17:35:26 -070091 bool has_opened_event_tag_map_ = false;
Tom Cherryfb1373a2019-10-29 07:05:24 -070092
93 // For the related --regex, --max-count, --print
94 std::unique_ptr<std::regex> regex_;
95 size_t max_count_ = 0; // 0 means "infinite"
96 size_t print_count_ = 0;
97 bool print_it_anyways_ = false;
98
99 // For PrintDividers()
100 log_id_t last_printed_id_ = LOG_ID_MAX;
101 bool printed_start_[LOG_ID_MAX] = {};
102
103 bool debug_ = false;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800104};
105
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800106// logd prefixes records with a length field
The Android Open Source Project190995d2009-03-03 19:32:55 -0800107#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
108
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800109enum helpType { HELP_FALSE, HELP_TRUE, HELP_FORMAT };
Mark Salyzyn604679a2016-10-18 11:30:11 -0700110
Tom Cherryb1cf4282019-10-24 17:35:26 -0700111// if show_help is set, newline required in fmt statement to transition to usage
112static void LogcatPanic(enum helpType showHelp, const char* fmt, ...) __printflike(2, 3)
113 __attribute__((__noreturn__));
Traian Schiau9f978602015-04-10 15:51:39 +0300114
Jaegeuk Kim64352f22019-07-04 18:09:38 -0700115#ifndef F2FS_IOC_SET_PIN_FILE
116#define F2FS_IOCTL_MAGIC 0xf5
117#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
118#endif
119
120static int openLogFile(const char* pathname, size_t sizeKB) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700121 int fd = open(pathname, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
Jaegeuk Kim64352f22019-07-04 18:09:38 -0700122 if (fd < 0) {
123 return fd;
124 }
125
126 // no need to check errors
127 __u32 set = 1;
128 ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
129 fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, (sizeKB << 10));
130 return fd;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800131}
132
Tom Cherryb1cf4282019-10-24 17:35:26 -0700133void Logcat::RotateLogs() {
The Android Open Source Project190995d2009-03-03 19:32:55 -0800134 // Can't rotate logs if we're not outputting to a file
Tom Cherryb1cf4282019-10-24 17:35:26 -0700135 if (!output_file_name_) return;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800136
Tom Cherryb1cf4282019-10-24 17:35:26 -0700137 output_fd_.reset();
The Android Open Source Project190995d2009-03-03 19:32:55 -0800138
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800139 // Compute the maximum number of digits needed to count up to
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800140 // maxRotatedLogs in decimal. eg:
141 // maxRotatedLogs == 30
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800142 // -> log10(30) == 1.477
143 // -> maxRotationCountDigits == 2
Tom Cherryb1cf4282019-10-24 17:35:26 -0700144 int max_rotation_count_digits =
145 max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
Aristidis Papaioannouf7cc6622014-10-16 22:19:55 -0700146
Tom Cherryb1cf4282019-10-24 17:35:26 -0700147 for (int i = max_rotated_logs_; i > 0; i--) {
148 std::string file1 =
149 StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800150
Mark Salyzyn2a1233e2016-08-03 14:20:41 -0700151 std::string file0;
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800152 if (!(i - 1)) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700153 file0 = output_file_name_;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800154 } else {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700155 file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800156 }
157
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800158 if (!file0.length() || !file1.length()) {
Traian Schiau9f978602015-04-10 15:51:39 +0300159 perror("while rotating log files");
160 break;
161 }
162
Tom Cherryb1cf4282019-10-24 17:35:26 -0700163 int err = rename(file0.c_str(), file1.c_str());
The Android Open Source Project190995d2009-03-03 19:32:55 -0800164
165 if (err < 0 && errno != ENOENT) {
166 perror("while rotating log files");
167 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800168 }
169
Tom Cherryb1cf4282019-10-24 17:35:26 -0700170 output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
The Android Open Source Project190995d2009-03-03 19:32:55 -0800171
Tom Cherryb1cf4282019-10-24 17:35:26 -0700172 if (!output_fd_.ok()) {
173 LogcatPanic(HELP_FALSE, "couldn't open output file");
Mark Salyzyn7e0bbab2017-02-17 13:15:51 -0800174 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800175
Tom Cherryb1cf4282019-10-24 17:35:26 -0700176 out_byte_count_ = 0;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800177}
178
Tom Cherryfb1373a2019-10-29 07:05:24 -0700179void Logcat::ProcessBuffer(struct log_msg* buf) {
Mathias Agopianb9218fb2010-03-17 16:10:26 -0700180 int bytesWritten = 0;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800181 int err;
182 AndroidLogEntry entry;
183 char binaryMsgBuf[1024];
184
Tom Cherryfb1373a2019-10-29 07:05:24 -0700185 bool is_binary =
186 buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
187
188 if (is_binary) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700189 if (!event_tag_map_ && !has_opened_event_tag_map_) {
190 event_tag_map_.reset(android_openEventTagMap(nullptr));
191 has_opened_event_tag_map_ = true;
Mark Salyzyn784d64f2015-02-26 14:33:35 -0800192 }
Tom Cherryb1cf4282019-10-24 17:35:26 -0700193 err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
Tom Cherry47856dd2019-10-15 16:53:11 -0700194 binaryMsgBuf, sizeof(binaryMsgBuf));
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800195 // printf(">>> pri=%d len=%d msg='%s'\n",
The Android Open Source Project190995d2009-03-03 19:32:55 -0800196 // entry.priority, entry.messageLen, entry.message);
197 } else {
Tom Cherry47856dd2019-10-15 16:53:11 -0700198 err = android_log_processLogBuffer(&buf->entry, &entry);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800199 }
Tom Cherryb1cf4282019-10-24 17:35:26 -0700200 if (err < 0 && !debug_) return;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800201
Tom Cherryb1cf4282019-10-24 17:35:26 -0700202 if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
203 entry.priority)) {
204 bool match = !regex_ ||
205 std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
Joe Onorato400da4a2010-03-01 09:11:54 -0800206
Tom Cherryb1cf4282019-10-24 17:35:26 -0700207 print_count_ += match;
208 if (match || print_it_anyways_) {
209 bytesWritten = android_log_printLogLine(logformat_.get(), output_fd_.get(), &entry);
Casey Dahlined028f92016-03-17 14:04:52 -0700210
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700211 if (bytesWritten < 0) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700212 LogcatPanic(HELP_FALSE, "output error");
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700213 }
Joe Onorato400da4a2010-03-01 09:11:54 -0800214 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800215 }
216
Tom Cherryb1cf4282019-10-24 17:35:26 -0700217 out_byte_count_ += bytesWritten;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800218
Tom Cherryb1cf4282019-10-24 17:35:26 -0700219 if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
220 RotateLogs();
The Android Open Source Project190995d2009-03-03 19:32:55 -0800221 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800222}
223
Tom Cherryfb1373a2019-10-29 07:05:24 -0700224void Logcat::PrintDividers(log_id_t log_id, bool print_dividers) {
225 if (log_id == last_printed_id_ || print_binary_) {
226 return;
Joe Onoratod23b9cf2010-02-26 10:04:23 -0800227 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700228 if (!printed_start_[log_id] || print_dividers) {
229 if (dprintf(output_fd_.get(), "--------- %s %s\n",
230 printed_start_[log_id] ? "switch to" : "beginning of",
231 android_log_id_to_name(log_id)) < 0) {
232 LogcatPanic(HELP_FALSE, "output error");
233 }
234 }
235 last_printed_id_ = log_id;
236 printed_start_[log_id] = true;
Joe Onoratod23b9cf2010-02-26 10:04:23 -0800237}
238
Tom Cherryb1cf4282019-10-24 17:35:26 -0700239void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
240 if (!output_file_name_) return;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800241
Mark Salyzyn60231da2016-08-04 07:53:52 -0700242 if (blocking) {
243 // Lower priority and set to batch scheduling if we are saving
244 // the logs into files and taking continuous content.
Tom Cherryb1cf4282019-10-24 17:35:26 -0700245 if (set_sched_policy(0, SP_BACKGROUND) < 0) {
246 fprintf(stderr, "failed to set background scheduling policy\n");
Mark Salyzyn38fc72c2015-06-02 07:57:16 -0700247 }
248
Tom Cherryb1cf4282019-10-24 17:35:26 -0700249 struct sched_param param = {};
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800250 if (sched_setscheduler((pid_t)0, SCHED_BATCH, &param) < 0) {
Mark Salyzyn38fc72c2015-06-02 07:57:16 -0700251 fprintf(stderr, "failed to set to batch scheduler\n");
252 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800253
Tom Cherryb1cf4282019-10-24 17:35:26 -0700254 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
255 fprintf(stderr, "failed set to priority\n");
Riley Andrews53fe1b02015-06-08 23:36:34 -0700256 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800257 }
Mark Salyzyn60231da2016-08-04 07:53:52 -0700258
Tom Cherryb1cf4282019-10-24 17:35:26 -0700259 output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
Mark Salyzyn60231da2016-08-04 07:53:52 -0700260
Tom Cherryb1cf4282019-10-24 17:35:26 -0700261 if (!output_fd_.ok()) {
262 LogcatPanic(HELP_FALSE, "couldn't open output file");
Mark Salyzyn60231da2016-08-04 07:53:52 -0700263 }
264
265 struct stat statbuf;
Tom Cherryb1cf4282019-10-24 17:35:26 -0700266 if (fstat(output_fd_.get(), &statbuf) == -1) {
267 output_fd_.reset();
268 LogcatPanic(HELP_FALSE, "couldn't get output file stat\n");
Mark Salyzyn60231da2016-08-04 07:53:52 -0700269 }
270
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800271 if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700272 output_fd_.reset();
273 LogcatPanic(HELP_FALSE, "invalid output file stat\n");
Mark Salyzyn60231da2016-08-04 07:53:52 -0700274 }
275
Tom Cherryb1cf4282019-10-24 17:35:26 -0700276 out_byte_count_ = statbuf.st_size;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800277}
278
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800279// clang-format off
Tom Cherryb1cf4282019-10-24 17:35:26 -0700280static void show_help() {
281 const char* cmd = getprogname();
The Android Open Source Project190995d2009-03-03 19:32:55 -0800282
Tom Cherryb1cf4282019-10-24 17:35:26 -0700283 fprintf(stderr, "Usage: %s [options] [filterspecs]\n", cmd);
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800284
Tom Cherrya59bde42019-11-21 10:31:06 -0800285 fprintf(stderr, R"init(
286General options:
287 -b, --buffer=<buffer> Request alternate ring buffer(s):
288 main system radio events crash default all
289 Additionally, 'kernel' for userdebug and eng builds, and
290 'security' for Device Owner installations.
291 Multiple -b parameters or comma separated list of buffers are
292 allowed. Buffers are interleaved.
293 Default -b main,system,crash,kernel.
294 -L, --last Dump logs from prior to last reboot from pstore.
295 -c, --clear Clear (flush) the entire log and exit.
296 if -f is specified, clear the specified file and its related rotated
297 log files instead.
298 if -L is specified, clear pstore log instead.
299 -d Dump the log and then exit (don't block).
300 --pid=<pid> Only print logs from the given pid.
301 --wrap Sleep for 2 hours or when buffer about to wrap whichever
302 comes first. Improves efficiency of polling by providing
303 an about-to-wrap wakeup.
304
305Formatting:
306 -v, --format=<format> Sets log print format verb and adverbs, where <format> is one of:
307 brief help long process raw tag thread threadtime time
308 Modifying adverbs can be added:
309 color descriptive epoch monotonic printable uid usec UTC year zone
310 Multiple -v parameters or comma separated list of format and format
311 modifiers are allowed.
312 -D, --dividers Print dividers between each log buffer.
313 -B, --binary Output the log in binary.
314
315Outfile files:
316 -f, --file=<file> Log to file instead of stdout.
317 -r, --rotate-kbytes=<n> Rotate log every <n> kbytes. Requires -f option.
318 -n, --rotate-count=<count> Sets max number of rotated logs to <count>, default 4.
319 --id=<id> If the signature <id> for logging to file changes, then clear the
320 associated files and continue.
321
322Logd control:
323 These options send a control message to the logd daemon on device, print its return message if
324 applicable, then exit. They are incompatible with -L, as these attributes do not apply to pstore.
325 -g, --buffer-size Get the size of the ring buffers within logd.
326 -G, --buffer-size=<size> Set size of a ring buffer in logd. May suffix with K or M.
327 This can individually control each buffer's size with -b.
328 -S, --statistics Output statistics.
329 --pid can be used to provide pid specific stats.
330 -p, --prune Print prune white and ~black list. Service is specified as UID,
331 UID/PID or /PID. Weighed for quicker pruning if prefix with ~,
332 otherwise weighed for longevity if unadorned. All other pruning
333 activity is oldest first. Special case ~! represents an automatic
334 quicker pruning for the noisiest UID as determined by the current
335 statistics.
336 -P, --prune='<list> ...' Set prune white and ~black list, using same format as listed above.
337 Must be quoted.
338
339Filtering:
340 -s Set default filter to silent. Equivalent to filterspec '*:S'
341 -e, --regex=<expr> Only print lines where the log message matches <expr> where <expr> is
342 an ECMAScript regular expression.
343 -m, --max-count=<count> Quit after printing <count> lines. This is meant to be paired with
344 --regex, but will work on its own.
345 --print This option is only applicable when --regex is set and only useful if
346 --max-count is also provided.
347 With --print, logcat will print all messages even if they do not
348 match the regex. Logcat will quit after printing the max-count number
349 of lines that match the regex.
350 -t <count> Print only the most recent <count> lines (implies -d).
351 -t '<time>' Print the lines since specified time (implies -d).
352 -T <count> Print only the most recent <count> lines (does not imply -d).
353 -T '<time>' Print the lines since specified time (not imply -d).
354 count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
355 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format.
356)init");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800357
Tom Cherryb1cf4282019-10-24 17:35:26 -0700358 fprintf(stderr, "\nfilterspecs are a series of \n"
The Android Open Source Project190995d2009-03-03 19:32:55 -0800359 " <tag>[:priority]\n\n"
360 "where <tag> is a log component tag (or * for all) and priority is:\n"
Mark Salyzyn438b8222015-03-09 09:32:56 -0700361 " V Verbose (default for <tag>)\n"
362 " D Debug (default for '*')\n"
The Android Open Source Project190995d2009-03-03 19:32:55 -0800363 " I Info\n"
364 " W Warn\n"
365 " E Error\n"
366 " F Fatal\n"
Mark Salyzyn438b8222015-03-09 09:32:56 -0700367 " S Silent (suppress all output)\n"
368 "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
369 "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
370 "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
371 "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
372 "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
Mark Salyzyndd569af2014-09-16 09:15:15 -0700373 "or defaults to \"threadtime\"\n\n");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800374}
375
Tom Cherryb1cf4282019-10-24 17:35:26 -0700376static void show_format_help() {
377 fprintf(stderr,
Mark Salyzyn604679a2016-10-18 11:30:11 -0700378 "-v <format>, --format=<format> options:\n"
379 " Sets log print format verb and adverbs, where <format> is:\n"
380 " brief long process raw tag thread threadtime time\n"
381 " and individually flagged modifying adverbs can be added:\n"
382 " color descriptive epoch monotonic printable uid usec UTC year zone\n"
383 "\nSingle format verbs:\n"
384 " brief — Display priority/tag and PID of the process issuing the message.\n"
385 " long — Display all metadata fields, separate messages with blank lines.\n"
386 " process — Display PID only.\n"
387 " raw — Display the raw log message, with no other metadata fields.\n"
388 " tag — Display the priority/tag only.\n"
Mark Salyzyn56ff3fa2017-05-15 13:40:33 -0700389 " thread — Display priority, PID and TID of process issuing the message.\n"
Mark Salyzyn604679a2016-10-18 11:30:11 -0700390 " threadtime — Display the date, invocation time, priority, tag, and the PID\n"
391 " and TID of the thread issuing the message. (the default format).\n"
392 " time — Display the date, invocation time, priority/tag, and PID of the\n"
393 " process issuing the message.\n"
394 "\nAdverb modifiers can be used in combination:\n"
395 " color — Display in highlighted color to match priority. i.e. \x1B[38;5;231mVERBOSE\n"
396 " \x1B[38;5;75mDEBUG \x1B[38;5;40mINFO \x1B[38;5;166mWARNING \x1B[38;5;196mERROR FATAL\x1B[0m\n"
397 " descriptive — events logs only, descriptions from event-log-tags database.\n"
398 " epoch — Display time as seconds since Jan 1 1970.\n"
399 " monotonic — Display time as cpu seconds since last boot.\n"
400 " printable — Ensure that any binary logging content is escaped.\n"
401 " uid — If permitted, display the UID or Android ID of logged process.\n"
402 " usec — Display time down the microsecond precision.\n"
403 " UTC — Display time as UTC.\n"
404 " year — Add the year to the displayed time.\n"
405 " zone — Add the local timezone to the displayed time.\n"
406 " \"<zone>\" — Print using this public named timezone (experimental).\n\n"
407 );
408}
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800409// clang-format on
Mark Salyzyn604679a2016-10-18 11:30:11 -0700410
Tom Cherryb1cf4282019-10-24 17:35:26 -0700411int Logcat::SetLogFormat(const char* format_string) {
412 AndroidLogPrintFormat format = android_log_formatFromString(format_string);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800413
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800414 // invalid string?
415 if (format == FORMAT_OFF) return -1;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800416
Tom Cherryb1cf4282019-10-24 17:35:26 -0700417 return android_log_setPrintFormat(logformat_.get(), format);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800418}
419
Wei Wang8b584172018-09-05 11:05:57 -0700420static std::pair<unsigned long, const char*> format_of_size(unsigned long value) {
421 static const char multipliers[][3] = {{""}, {"Ki"}, {"Mi"}, {"Gi"}};
422 size_t i;
Mark Salyzyn4e756fb2014-05-06 07:34:59 -0700423 for (i = 0;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800424 (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
425 value /= 1024, ++i)
426 ;
Wei Wang8b584172018-09-05 11:05:57 -0700427 return std::make_pair(value, multipliers[i]);
Mark Salyzyn4e756fb2014-05-06 07:34:59 -0700428}
429
Tom Cherryb1cf4282019-10-24 17:35:26 -0700430static void LogcatPanic(enum helpType showHelp, const char* fmt, ...) {
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800431 va_list args;
Mark Salyzynf4fbfad2015-04-13 09:27:57 -0700432 va_start(args, fmt);
Tom Cherryb1cf4282019-10-24 17:35:26 -0700433 vfprintf(stderr, fmt, args);
Mark Salyzynf4fbfad2015-04-13 09:27:57 -0700434 va_end(args);
Traian Schiau9f978602015-04-10 15:51:39 +0300435
Mark Salyzyn604679a2016-10-18 11:30:11 -0700436 switch (showHelp) {
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800437 case HELP_TRUE:
Tom Cherryb1cf4282019-10-24 17:35:26 -0700438 show_help();
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800439 break;
440 case HELP_FORMAT:
Tom Cherryb1cf4282019-10-24 17:35:26 -0700441 show_format_help();
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800442 break;
443 case HELP_FALSE:
444 default:
445 break;
Traian Schiau9f978602015-04-10 15:51:39 +0300446 }
447
Tom Cherryb1cf4282019-10-24 17:35:26 -0700448 exit(EXIT_FAILURE);
Traian Schiau9f978602015-04-10 15:51:39 +0300449}
450
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800451static char* parseTime(log_time& t, const char* cp) {
452 char* ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800453 if (ep) return ep;
Mark Salyzyn4d0473f2015-08-31 15:53:41 -0700454 ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800455 if (ep) return ep;
Mark Salyzyn4d0473f2015-08-31 15:53:41 -0700456 return t.strptime(cp, "%s.%q");
Mark Salyzyneb0456d2015-08-31 08:01:33 -0700457}
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700458
Mark Salyzyn05b88232016-08-04 07:43:46 -0700459// Find last logged line in <outputFileName>, or <outputFileName>.1
Mark Salyzyn79b0a152017-03-02 15:09:41 -0800460static log_time lastLogTime(const char* outputFileName) {
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700461 log_time retval(log_time::EPOCH);
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800462 if (!outputFileName) return retval;
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700463
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700464 std::string directory;
Mark Salyzyn79b0a152017-03-02 15:09:41 -0800465 const char* file = strrchr(outputFileName, '/');
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700466 if (!file) {
467 directory = ".";
468 file = outputFileName;
469 } else {
Mark Salyzyn79b0a152017-03-02 15:09:41 -0800470 directory = std::string(outputFileName, file - outputFileName);
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700471 ++file;
472 }
Mark Salyzyn17475732016-04-01 07:52:20 -0700473
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800474 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()),
475 closedir);
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800476 if (!dir.get()) return retval;
Mark Salyzyn17475732016-04-01 07:52:20 -0700477
Mark Salyzyn05b88232016-08-04 07:43:46 -0700478 log_time now(android_log_clockid());
Mark Salyzyn17475732016-04-01 07:52:20 -0700479
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700480 size_t len = strlen(file);
481 log_time modulo(0, NS_PER_SEC);
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800482 struct dirent* dp;
Mark Salyzyn17475732016-04-01 07:52:20 -0700483
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800484 while (!!(dp = readdir(dir.get()))) {
485 if ((dp->d_type != DT_REG) || !!strncmp(dp->d_name, file, len) ||
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800486 (dp->d_name[len] && ((dp->d_name[len] != '.') ||
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800487 (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) {
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700488 continue;
489 }
490
491 std::string file_name = directory;
492 file_name += "/";
493 file_name += dp->d_name;
494 std::string file;
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800495 if (!android::base::ReadFileToString(file_name, &file)) continue;
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700496
497 bool found = false;
498 for (const auto& line : android::base::Split(file, "\n")) {
499 log_time t(log_time::EPOCH);
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800500 char* ep = parseTime(t, line.c_str());
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800501 if (!ep || (*ep != ' ')) continue;
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700502 // determine the time precision of the logs (eg: msec or usec)
503 for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
504 if (t.tv_nsec % (mod * 10)) {
505 modulo.tv_nsec = mod;
506 break;
507 }
508 }
509 // We filter any times later than current as we may not have the
510 // year stored with each log entry. Also, since it is possible for
511 // entries to be recorded out of order (very rare) we select the
512 // maximum we find just in case.
513 if ((t < now) && (t > retval)) {
514 retval = t;
515 found = true;
516 }
517 }
518 // We count on the basename file to be the definitive end, so stop here.
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800519 if (!dp->d_name[len] && found) break;
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700520 }
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800521 if (retval == log_time::EPOCH) return retval;
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700522 // tail_time prints matching or higher, round up by the modulo to prevent
523 // a replay of the last entry we have just checked.
524 retval += modulo;
525 return retval;
526}
527
Tom Cherryfb1373a2019-10-29 07:05:24 -0700528void ReportErrorName(const std::string& name, bool allow_security,
529 std::vector<std::string>* errors) {
530 if (allow_security || name != "security") {
531 errors->emplace_back(name);
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800532 }
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800533}
Traian Schiau9f978602015-04-10 15:51:39 +0300534
Tom Cherryb1cf4282019-10-24 17:35:26 -0700535int Logcat::Run(int argc, char** argv) {
Mark Salyzynd5920022017-02-28 09:20:31 -0800536 bool hasSetLogFormat = false;
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800537 bool clearLog = false;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700538 bool security_buffer_selected =
539 false; // Do not report errors on the security buffer unless it is explicitly named.
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800540 bool getLogSize = false;
541 bool getPruneList = false;
542 bool printStatistics = false;
543 bool printDividers = false;
Mark Salyzync89839a2014-02-11 12:29:31 -0800544 unsigned long setLogSize = 0;
Mark Salyzyn79b0a152017-03-02 15:09:41 -0800545 const char* setPruneList = nullptr;
546 const char* setId = nullptr;
Mark Salyzyn4bdf2532015-01-26 10:46:44 -0800547 int mode = ANDROID_LOG_RDONLY;
Mark Salyzynd2a03b52017-02-10 13:09:07 -0800548 std::string forceFilters;
Traian Schiau9f978602015-04-10 15:51:39 +0300549 size_t tail_lines = 0;
Mark Salyzyn9addf592014-02-14 16:05:05 -0800550 log_time tail_time(log_time::EPOCH);
Kristian Monsen694cdf62015-06-05 14:10:12 -0700551 size_t pid = 0;
Casey Dahlined028f92016-03-17 14:04:52 -0700552 bool got_t = false;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700553 unsigned id_mask = 0;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800554
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800555 if (argc == 2 && !strcmp(argv[1], "--help")) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700556 show_help();
557 return EXIT_SUCCESS;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800558 }
559
Mark Salyzynd5920022017-02-28 09:20:31 -0800560 // meant to catch comma-delimited values, but cast a wider
561 // net for stability dealing with possible mistaken inputs.
562 static const char delimiters[] = ",:; \t\n\r\f";
563
Elliott Hughes442d8582018-06-15 15:16:20 -0700564 optind = 0;
565 while (true) {
Kristian Monsen694cdf62015-06-05 14:10:12 -0700566 int option_index = 0;
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700567 // list of long-argument only strings for later comparison
Kristian Monsen694cdf62015-06-05 14:10:12 -0700568 static const char pid_str[] = "pid";
Mark Salyzyn14369232016-11-16 15:28:31 -0800569 static const char debug_str[] = "debug";
Mark Salyzyn175773d2016-08-03 14:20:41 -0700570 static const char id_str[] = "id";
Mark Salyzyn712caab2015-11-30 13:48:56 -0800571 static const char wrap_str[] = "wrap";
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700572 static const char print_str[] = "print";
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800573 // clang-format off
Kristian Monsen694cdf62015-06-05 14:10:12 -0700574 static const struct option long_options[] = {
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800575 { "binary", no_argument, nullptr, 'B' },
576 { "buffer", required_argument, nullptr, 'b' },
577 { "buffer-size", optional_argument, nullptr, 'g' },
578 { "clear", no_argument, nullptr, 'c' },
579 { debug_str, no_argument, nullptr, 0 },
580 { "dividers", no_argument, nullptr, 'D' },
581 { "file", required_argument, nullptr, 'f' },
582 { "format", required_argument, nullptr, 'v' },
Mark Salyzyn17475732016-04-01 07:52:20 -0700583 // hidden and undocumented reserved alias for --regex
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800584 { "grep", required_argument, nullptr, 'e' },
Mark Salyzyn12d83062016-03-30 09:15:09 -0700585 // hidden and undocumented reserved alias for --max-count
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800586 { "head", required_argument, nullptr, 'm' },
Mark Salyzyn6a3d5492017-04-03 09:30:20 -0700587 { "help", no_argument, nullptr, 'h' },
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800588 { id_str, required_argument, nullptr, 0 },
589 { "last", no_argument, nullptr, 'L' },
590 { "max-count", required_argument, nullptr, 'm' },
591 { pid_str, required_argument, nullptr, 0 },
592 { print_str, no_argument, nullptr, 0 },
593 { "prune", optional_argument, nullptr, 'p' },
594 { "regex", required_argument, nullptr, 'e' },
595 { "rotate-count", required_argument, nullptr, 'n' },
596 { "rotate-kbytes", required_argument, nullptr, 'r' },
597 { "statistics", no_argument, nullptr, 'S' },
Mark Salyzyn12d83062016-03-30 09:15:09 -0700598 // hidden and undocumented reserved alias for -t
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800599 { "tail", required_argument, nullptr, 't' },
Mark Salyzyn712caab2015-11-30 13:48:56 -0800600 // support, but ignore and do not document, the optional argument
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800601 { wrap_str, optional_argument, nullptr, 0 },
602 { nullptr, 0, nullptr, 0 }
Kristian Monsen694cdf62015-06-05 14:10:12 -0700603 };
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800604 // clang-format on
Kristian Monsen694cdf62015-06-05 14:10:12 -0700605
Elliott Hughes442d8582018-06-15 15:16:20 -0700606 int c = getopt_long(argc, argv, ":cdDhLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", long_options,
607 &option_index);
608 if (c == -1) break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800609
Elliott Hughes442d8582018-06-15 15:16:20 -0700610 switch (c) {
Kristian Monsen694cdf62015-06-05 14:10:12 -0700611 case 0:
Mark Salyzyn175773d2016-08-03 14:20:41 -0700612 // only long options
Kristian Monsen694cdf62015-06-05 14:10:12 -0700613 if (long_options[option_index].name == pid_str) {
Steven Moreland36f05952019-08-02 10:13:57 -0700614 if (pid != 0) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700615 LogcatPanic(HELP_TRUE, "Only supports one PID argument.\n");
Steven Moreland36f05952019-08-02 10:13:57 -0700616 }
617
Kristian Monsen694cdf62015-06-05 14:10:12 -0700618 // ToDo: determine runtime PID_MAX?
Tom Cherryfb1373a2019-10-29 07:05:24 -0700619 if (!ParseUint(optarg, &pid) || pid < 1) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700620 LogcatPanic(HELP_TRUE, "%s %s out of range\n",
621 long_options[option_index].name, optarg);
Kristian Monsen694cdf62015-06-05 14:10:12 -0700622 }
623 break;
624 }
Mark Salyzyn712caab2015-11-30 13:48:56 -0800625 if (long_options[option_index].name == wrap_str) {
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800626 mode |= ANDROID_LOG_WRAP | ANDROID_LOG_RDONLY |
Mark Salyzyn712caab2015-11-30 13:48:56 -0800627 ANDROID_LOG_NONBLOCK;
628 // ToDo: implement API that supports setting a wrap timeout
629 size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
Tom Cherryfb1373a2019-10-29 07:05:24 -0700630 if (optarg && (!ParseUint(optarg, &dummy) || dummy < 1)) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700631 LogcatPanic(HELP_TRUE, "%s %s out of range\n",
632 long_options[option_index].name, optarg);
Mark Salyzyn712caab2015-11-30 13:48:56 -0800633 }
Tom Cherryb1cf4282019-10-24 17:35:26 -0700634 if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
635 fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
636 long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
637 dummy);
Mark Salyzyn712caab2015-11-30 13:48:56 -0800638 }
639 break;
640 }
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700641 if (long_options[option_index].name == print_str) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700642 print_it_anyways_ = true;
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700643 break;
644 }
Mark Salyzyn14369232016-11-16 15:28:31 -0800645 if (long_options[option_index].name == debug_str) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700646 debug_ = true;
Mark Salyzyn14369232016-11-16 15:28:31 -0800647 break;
648 }
Mark Salyzyn175773d2016-08-03 14:20:41 -0700649 if (long_options[option_index].name == id_str) {
Elliott Hughes442d8582018-06-15 15:16:20 -0700650 setId = (optarg && optarg[0]) ? optarg : nullptr;
Mark Salyzyn175773d2016-08-03 14:20:41 -0700651 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800652 break;
Kristian Monsen694cdf62015-06-05 14:10:12 -0700653
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -0800654 case 's':
The Android Open Source Project190995d2009-03-03 19:32:55 -0800655 // default to all silent
Tom Cherryb1cf4282019-10-24 17:35:26 -0700656 android_log_addFilterRule(logformat_.get(), "*:s");
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800657 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800658
659 case 'c':
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800660 clearLog = true;
Mark Salyzyn4bdf2532015-01-26 10:46:44 -0800661 mode |= ANDROID_LOG_WRONLY;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800662 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800663
Mark Salyzyn66460fc2014-12-15 10:01:31 -0800664 case 'L':
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800665 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE |
666 ANDROID_LOG_NONBLOCK;
667 break;
Mark Salyzyn66460fc2014-12-15 10:01:31 -0800668
The Android Open Source Project190995d2009-03-03 19:32:55 -0800669 case 'd':
Mark Salyzyn4bdf2532015-01-26 10:46:44 -0800670 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800671 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800672
Dan Egnorcce2b082010-03-11 20:32:17 -0800673 case 't':
Casey Dahlined028f92016-03-17 14:04:52 -0700674 got_t = true;
Mark Salyzyn4bdf2532015-01-26 10:46:44 -0800675 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
Chih-Hung Hsieh6d461422018-09-13 11:08:41 -0700676 FALLTHROUGH_INTENDED;
Mark Salyzyn2256e2f2013-12-09 13:47:00 -0800677 case 'T':
Elliott Hughes442d8582018-06-15 15:16:20 -0700678 if (strspn(optarg, "0123456789") != strlen(optarg)) {
679 char* cp = parseTime(tail_time, optarg);
Mark Salyzyn9addf592014-02-14 16:05:05 -0800680 if (!cp) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700681 LogcatPanic(HELP_FALSE, "-%c \"%s\" not in time format\n", c, optarg);
Mark Salyzyn9addf592014-02-14 16:05:05 -0800682 }
683 if (*cp) {
Elliott Hughes442d8582018-06-15 15:16:20 -0700684 char ch = *cp;
Mark Salyzyn9addf592014-02-14 16:05:05 -0800685 *cp = '\0';
Tom Cherryb1cf4282019-10-24 17:35:26 -0700686 fprintf(stderr, "WARNING: -%c \"%s\"\"%c%s\" time truncated\n", c, optarg,
687 ch, cp + 1);
Elliott Hughes442d8582018-06-15 15:16:20 -0700688 *cp = ch;
Mark Salyzyn9addf592014-02-14 16:05:05 -0800689 }
690 } else {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700691 if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700692 fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
Mark Salyzyn9addf592014-02-14 16:05:05 -0800693 tail_lines = 1;
694 }
695 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800696 break;
Dan Egnorcce2b082010-03-11 20:32:17 -0800697
Mark Salyzyn1ff18092015-01-26 13:41:33 -0800698 case 'D':
699 printDividers = true;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800700 break;
Mark Salyzyn1ff18092015-01-26 13:41:33 -0800701
Casey Dahlin4cf025a2016-03-17 16:18:55 -0700702 case 'e':
Tom Cherryb1cf4282019-10-24 17:35:26 -0700703 regex_.reset(new std::regex(optarg));
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800704 break;
Casey Dahlin4cf025a2016-03-17 16:18:55 -0700705
Casey Dahlined028f92016-03-17 14:04:52 -0700706 case 'm': {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700707 if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700708 LogcatPanic(HELP_FALSE, "-%c \"%s\" isn't an integer greater than zero\n", c,
709 optarg);
Casey Dahlined028f92016-03-17 14:04:52 -0700710 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800711 } break;
Casey Dahlined028f92016-03-17 14:04:52 -0700712
The Android Open Source Project190995d2009-03-03 19:32:55 -0800713 case 'g':
Elliott Hughes442d8582018-06-15 15:16:20 -0700714 if (!optarg) {
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800715 getLogSize = true;
Mark Salyzynaef4c7e2015-11-30 12:57:56 -0800716 break;
717 }
Chih-Hung Hsieh6d461422018-09-13 11:08:41 -0700718 FALLTHROUGH_INTENDED;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800719
Mark Salyzync89839a2014-02-11 12:29:31 -0800720 case 'G': {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700721 if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700722 LogcatPanic(HELP_FALSE, "ERROR: -G <num><multiplier>\n");
Mark Salyzync89839a2014-02-11 12:29:31 -0800723 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800724 } break;
Mark Salyzync89839a2014-02-11 12:29:31 -0800725
726 case 'p':
Elliott Hughes442d8582018-06-15 15:16:20 -0700727 if (!optarg) {
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800728 getPruneList = true;
Mark Salyzynaef4c7e2015-11-30 12:57:56 -0800729 break;
730 }
Chih-Hung Hsieh6d461422018-09-13 11:08:41 -0700731 FALLTHROUGH_INTENDED;
Mark Salyzync89839a2014-02-11 12:29:31 -0800732
733 case 'P':
Elliott Hughes442d8582018-06-15 15:16:20 -0700734 setPruneList = optarg;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800735 break;
Mark Salyzync89839a2014-02-11 12:29:31 -0800736
Tom Cherryfb1373a2019-10-29 07:05:24 -0700737 case 'b':
738 for (const auto& buffer : Split(optarg, delimiters)) {
739 if (buffer == "default") {
740 id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
741 } else if (buffer == "all") {
742 id_mask = -1;
Mark Salyzyn9ca3be32016-04-11 14:03:48 -0700743 } else {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700744 log_id_t log_id = android_name_to_log_id(buffer.c_str());
745 if (log_id >= LOG_ID_MAX) {
746 LogcatPanic(HELP_TRUE, "unknown buffer %s\n", buffer.c_str());
Mark Salyzynd774bce2014-02-06 14:48:50 -0800747 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700748 if (log_id == LOG_ID_SECURITY) {
749 security_buffer_selected = true;
Mark Salyzync9690862015-12-04 10:59:45 -0800750 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700751 id_mask |= (1 << log_id);
Joe Onoratod23b9cf2010-02-26 10:04:23 -0800752 }
Joe Onoratod23b9cf2010-02-26 10:04:23 -0800753 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700754 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800755
756 case 'B':
Tom Cherryb1cf4282019-10-24 17:35:26 -0700757 print_binary_ = 1;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800758 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800759
760 case 'f':
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800761 if ((tail_time == log_time::EPOCH) && !tail_lines) {
Elliott Hughes442d8582018-06-15 15:16:20 -0700762 tail_time = lastLogTime(optarg);
Mark Salyzyn3fa657e2015-05-27 07:39:56 -0700763 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800764 // redirect output to a file
Tom Cherryb1cf4282019-10-24 17:35:26 -0700765 output_file_name_ = optarg;
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800766 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800767
Mark Salyzynff5f4b12016-06-07 13:03:10 -0700768 case 'r':
Tom Cherryfb1373a2019-10-29 07:05:24 -0700769 if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700770 LogcatPanic(HELP_TRUE, "Invalid parameter \"%s\" to -r\n", optarg);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800771 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800772 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800773
Mark Salyzynff5f4b12016-06-07 13:03:10 -0700774 case 'n':
Tom Cherryfb1373a2019-10-29 07:05:24 -0700775 if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700776 LogcatPanic(HELP_TRUE, "Invalid parameter \"%s\" to -n\n", optarg);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800777 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800778 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800779
Tom Cherryfb1373a2019-10-29 07:05:24 -0700780 case 'v':
Elliott Hughes442d8582018-06-15 15:16:20 -0700781 if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700782 show_format_help();
783 return EXIT_SUCCESS;
Mark Salyzyn604679a2016-10-18 11:30:11 -0700784 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700785 for (const auto& arg : Split(optarg, delimiters)) {
786 int err = SetLogFormat(arg.c_str());
Mark Salyzynd5920022017-02-28 09:20:31 -0800787 if (err < 0) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700788 LogcatPanic(HELP_FORMAT, "Invalid parameter \"%s\" to -v\n", arg.c_str());
Mark Salyzynd5920022017-02-28 09:20:31 -0800789 }
Mark Salyzynd5920022017-02-28 09:20:31 -0800790 if (err) hasSetLogFormat = true;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800791 }
Tom Cherryfb1373a2019-10-29 07:05:24 -0700792 break;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800793
794 case 'Q':
bohu25889532017-02-21 14:31:19 -0800795#define LOGCAT_FILTER "androidboot.logcat="
796#define CONSOLE_PIPE_OPTION "androidboot.consolepipe="
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800797#define CONSOLE_OPTION "androidboot.console="
bohu25889532017-02-21 14:31:19 -0800798#define QEMU_PROPERTY "ro.kernel.qemu"
799#define QEMU_CMDLINE "qemu.cmdline"
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800800 // This is a *hidden* option used to start a version of logcat
801 // in an emulated device only. It basically looks for
802 // androidboot.logcat= on the kernel command line. If
803 // something is found, it extracts a log filter and uses it to
bohu25889532017-02-21 14:31:19 -0800804 // run the program. The logcat output will go to consolepipe if
805 // androiboot.consolepipe (e.g. qemu_pipe) is given, otherwise,
806 // it goes to androidboot.console (e.g. tty)
The Android Open Source Project190995d2009-03-03 19:32:55 -0800807 {
bohu25889532017-02-21 14:31:19 -0800808 // if not in emulator, exit quietly
809 if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700810 return EXIT_SUCCESS;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800811 }
Mark Salyzynd2a03b52017-02-10 13:09:07 -0800812
bohu25889532017-02-21 14:31:19 -0800813 std::string cmdline = android::base::GetProperty(QEMU_CMDLINE, "");
814 if (cmdline.empty()) {
815 android::base::ReadFileToString("/proc/cmdline", &cmdline);
816 }
817
818 const char* logcatFilter = strstr(cmdline.c_str(), LOGCAT_FILTER);
819 // if nothing found or invalid filters, exit quietly
820 if (!logcatFilter) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700821 return EXIT_SUCCESS;
bohu25889532017-02-21 14:31:19 -0800822 }
823
824 const char* p = logcatFilter + strlen(LOGCAT_FILTER);
Mark Salyzynd2a03b52017-02-10 13:09:07 -0800825 const char* q = strpbrk(p, " \t\n\r");
826 if (!q) q = p + strlen(p);
827 forceFilters = std::string(p, q);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800828
bohu25889532017-02-21 14:31:19 -0800829 // redirect our output to the emulator console pipe or console
830 const char* consolePipe =
831 strstr(cmdline.c_str(), CONSOLE_PIPE_OPTION);
Mark Salyzynd2a03b52017-02-10 13:09:07 -0800832 const char* console =
833 strstr(cmdline.c_str(), CONSOLE_OPTION);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800834
bohu25889532017-02-21 14:31:19 -0800835 if (consolePipe) {
836 p = consolePipe + strlen(CONSOLE_PIPE_OPTION);
837 } else if (console) {
838 p = console + strlen(CONSOLE_OPTION);
839 } else {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700840 return EXIT_FAILURE;
bohu25889532017-02-21 14:31:19 -0800841 }
842
Mark Salyzynd2a03b52017-02-10 13:09:07 -0800843 q = strpbrk(p, " \t\n\r");
844 int len = q ? q - p : strlen(p);
845 std::string devname = "/dev/" + std::string(p, len);
bohu25889532017-02-21 14:31:19 -0800846 std::string pipePurpose("pipe:logcat");
847 if (consolePipe) {
848 // example: "qemu_pipe,pipe:logcat"
849 // upon opening of /dev/qemu_pipe, the "pipe:logcat"
850 // string with trailing '\0' should be written to the fd
Chih-Hung Hsiehdd8aae62017-08-03 13:56:49 -0700851 size_t pos = devname.find(',');
bohu25889532017-02-21 14:31:19 -0800852 if (pos != std::string::npos) {
853 pipePurpose = devname.substr(pos + 1);
854 devname = devname.substr(0, pos);
855 }
856 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800857
Tom Cherryb1cf4282019-10-24 17:35:26 -0700858 fprintf(stderr, "logcat using %s\n", devname.c_str());
859
860 int fd = open(devname.c_str(), O_WRONLY | O_CLOEXEC);
861 if (fd < 0) {
862 break;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -0800863 }
Mark Salyzynd2a03b52017-02-10 13:09:07 -0800864
bohu25889532017-02-21 14:31:19 -0800865 if (consolePipe) {
866 // need the trailing '\0'
Tom Cherryb1cf4282019-10-24 17:35:26 -0700867 if (!android::base::WriteFully(fd, pipePurpose.c_str(),
868 pipePurpose.size() + 1)) {
869 close(fd);
870 return EXIT_FAILURE;
bohu25889532017-02-21 14:31:19 -0800871 }
872 }
Mark Salyzynd2a03b52017-02-10 13:09:07 -0800873 // close output and error channels, replace with console
Erwin Jansen613c7d42019-11-27 12:58:58 -0800874 dup2(fd, output_fd_.get());
Tom Cherryb1cf4282019-10-24 17:35:26 -0700875 dup2(fd, STDERR_FILENO);
876 close(fd);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800877 }
878 break;
879
Mark Salyzynd774bce2014-02-06 14:48:50 -0800880 case 'S':
Mark Salyzyn70cf66d2017-01-20 14:07:29 -0800881 printStatistics = true;
Mark Salyzynd774bce2014-02-06 14:48:50 -0800882 break;
883
Traian Schiau9f978602015-04-10 15:51:39 +0300884 case ':':
Tom Cherryb1cf4282019-10-24 17:35:26 -0700885 LogcatPanic(HELP_TRUE, "Option -%c needs an argument\n", optopt);
Traian Schiau9f978602015-04-10 15:51:39 +0300886
Mark Salyzyn6a3d5492017-04-03 09:30:20 -0700887 case 'h':
Tom Cherryb1cf4282019-10-24 17:35:26 -0700888 show_help();
889 show_format_help();
890 return EXIT_SUCCESS;
Mark Salyzyn6a3d5492017-04-03 09:30:20 -0700891
The Android Open Source Project190995d2009-03-03 19:32:55 -0800892 default:
Tom Cherryb1cf4282019-10-24 17:35:26 -0700893 LogcatPanic(HELP_TRUE, "Unrecognized Option %c\n", optopt);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800894 }
895 }
896
Tom Cherryb1cf4282019-10-24 17:35:26 -0700897 if (max_count_ && got_t) {
898 LogcatPanic(HELP_TRUE, "Cannot use -m (--max-count) and -t together\n");
Casey Dahlined028f92016-03-17 14:04:52 -0700899 }
Tom Cherryb1cf4282019-10-24 17:35:26 -0700900 if (print_it_anyways_ && (!regex_ || !max_count_)) {
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700901 // One day it would be nice if --print -v color and --regex <expr>
902 // could play with each other and show regex highlighted content.
Tom Cherryb1cf4282019-10-24 17:35:26 -0700903 fprintf(stderr,
904 "WARNING: "
905 "--print ignored, to be used in combination with\n"
906 " "
907 "--regex <expr> and --max-count <N>\n");
908 print_it_anyways_ = false;
Mark Salyzyn1181ec02016-03-30 09:38:31 -0700909 }
Casey Dahlined028f92016-03-17 14:04:52 -0700910
Tom Cherryfb1373a2019-10-29 07:05:24 -0700911 // If no buffers are specified, default to using these buffers.
912 if (id_mask == 0) {
913 id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
914 (1 << LOG_ID_KERNEL);
Joe Onoratod23b9cf2010-02-26 10:04:23 -0800915 }
916
Tom Cherryb1cf4282019-10-24 17:35:26 -0700917 if (log_rotate_size_kb_ != 0 && !output_file_name_) {
918 LogcatPanic(HELP_TRUE, "-r requires -f as well\n");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800919 }
920
Tom Cherryb1cf4282019-10-24 17:35:26 -0700921 if (setId != 0) {
922 if (!output_file_name_) {
923 LogcatPanic(HELP_TRUE, "--id='%s' requires -f as well\n", setId);
Mark Salyzyn175773d2016-08-03 14:20:41 -0700924 }
925
Tom Cherryb1cf4282019-10-24 17:35:26 -0700926 std::string file_name = StringPrintf("%s.id", output_file_name_);
Mark Salyzyn175773d2016-08-03 14:20:41 -0700927 std::string file;
928 bool file_ok = android::base::ReadFileToString(file_name, &file);
Mark Salyzynd8b454f2017-02-10 13:09:07 -0800929 android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
930 getuid(), getgid());
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800931 if (!file_ok || !file.compare(setId)) setId = nullptr;
Mark Salyzyn175773d2016-08-03 14:20:41 -0700932 }
The Android Open Source Project190995d2009-03-03 19:32:55 -0800933
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800934 if (!hasSetLogFormat) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700935 const char* logFormat = getenv("ANDROID_PRINTF_LOG");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800936
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800937 if (!!logFormat) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700938 for (const auto& arg : Split(logFormat, delimiters)) {
939 int err = SetLogFormat(arg.c_str());
Mark Salyzynd5920022017-02-28 09:20:31 -0800940 // environment should not cause crash of logcat
Tom Cherryb1cf4282019-10-24 17:35:26 -0700941 if (err < 0) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700942 fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
Mark Salyzynd5920022017-02-28 09:20:31 -0800943 }
Mark Salyzynd5920022017-02-28 09:20:31 -0800944 if (err > 0) hasSetLogFormat = true;
The Android Open Source Project190995d2009-03-03 19:32:55 -0800945 }
Mark Salyzynd5920022017-02-28 09:20:31 -0800946 }
947 if (!hasSetLogFormat) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700948 SetLogFormat("threadtime");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800949 }
950 }
951
Mark Salyzynd2a03b52017-02-10 13:09:07 -0800952 if (forceFilters.size()) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700953 int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
The Android Open Source Project190995d2009-03-03 19:32:55 -0800954 if (err < 0) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700955 LogcatPanic(HELP_FALSE, "Invalid filter expression in logcat args\n");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800956 }
Elliott Hughes442d8582018-06-15 15:16:20 -0700957 } else if (argc == optind) {
The Android Open Source Project190995d2009-03-03 19:32:55 -0800958 // Add from environment variable
Tom Cherryb1cf4282019-10-24 17:35:26 -0700959 const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800960
Mark Salyzyne5f043c2017-03-01 08:30:06 -0800961 if (!!env_tags_orig) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700962 int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800963
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -0800964 if (err < 0) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700965 LogcatPanic(HELP_TRUE, "Invalid filter expression in ANDROID_LOG_TAGS\n");
The Android Open Source Project190995d2009-03-03 19:32:55 -0800966 }
967 }
968 } else {
969 // Add from commandline
Elliott Hughes442d8582018-06-15 15:16:20 -0700970 for (int i = optind ; i < argc ; i++) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700971 int err = android_log_addFilterString(logformat_.get(), argv[i]);
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -0800972 if (err < 0) {
Tom Cherryb1cf4282019-10-24 17:35:26 -0700973 LogcatPanic(HELP_TRUE, "Invalid filter expression '%s'\n", argv[i]);
The Android Open Source Project190995d2009-03-03 19:32:55 -0800974 }
975 }
976 }
977
Tom Cherryf459c582019-11-14 08:56:39 -0800978 if (mode & ANDROID_LOG_PSTORE) {
979 if (clearLog) {
980 unlink("/sys/fs/pstore/pmsg-ramoops-0");
981 return EXIT_SUCCESS;
982 }
983 if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
984 LogcatPanic(HELP_TRUE, "-L is incompatible with -g/-G, -S, and -p/-P");
985 }
986 }
987
Tom Cherryfb1373a2019-10-29 07:05:24 -0700988 std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
989 nullptr, &android_logger_list_free};
Mark Salyzyn9addf592014-02-14 16:05:05 -0800990 if (tail_time != log_time::EPOCH) {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700991 logger_list.reset(android_logger_list_alloc_time(mode, tail_time, pid));
Mark Salyzyn9addf592014-02-14 16:05:05 -0800992 } else {
Tom Cherryfb1373a2019-10-29 07:05:24 -0700993 logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));
Mark Salyzyn9addf592014-02-14 16:05:05 -0800994 }
Mark Salyzyn7ccdb902015-09-16 15:34:00 -0700995 // We have three orthogonal actions below to clear, set log size and
996 // get log size. All sharing the same iteration loop.
Tom Cherryfb1373a2019-10-29 07:05:24 -0700997 std::vector<std::string> open_device_failures;
998 std::vector<std::string> clear_failures;
999 std::vector<std::string> set_size_failures;
1000 std::vector<std::string> get_size_failures;
1001
1002 for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
1003 if (!(id_mask & (1 << i))) continue;
1004 const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
1005
1006 auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
1007 if (logger == nullptr) {
1008 ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001009 continue;
The Android Open Source Project190995d2009-03-03 19:32:55 -08001010 }
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001011
Mark Salyzyn175773d2016-08-03 14:20:41 -07001012 if (clearLog || setId) {
Tom Cherryb1cf4282019-10-24 17:35:26 -07001013 if (output_file_name_) {
1014 int max_rotation_count_digits =
1015 max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
Mark Salyzyn7c73e752016-06-06 14:56:00 -07001016
Tom Cherryb1cf4282019-10-24 17:35:26 -07001017 for (int i = max_rotated_logs_; i >= 0; --i) {
Mark Salyzyn2a1233e2016-08-03 14:20:41 -07001018 std::string file;
Mark Salyzyn7c73e752016-06-06 14:56:00 -07001019
Mark Salyzyne5f043c2017-03-01 08:30:06 -08001020 if (!i) {
Tom Cherryb1cf4282019-10-24 17:35:26 -07001021 file = output_file_name_;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08001022 } else {
Tom Cherryb1cf4282019-10-24 17:35:26 -07001023 file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits,
1024 i);
Mark Salyzyn7c73e752016-06-06 14:56:00 -07001025 }
1026
Mark Salyzyne5f043c2017-03-01 08:30:06 -08001027 if (!file.length()) {
Mark Salyzyn7c73e752016-06-06 14:56:00 -07001028 perror("while clearing log files");
Tom Cherryfb1373a2019-10-29 07:05:24 -07001029 ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
Mark Salyzyn7c73e752016-06-06 14:56:00 -07001030 break;
1031 }
1032
Tom Cherryfb1373a2019-10-29 07:05:24 -07001033 int err = unlink(file.c_str());
Mark Salyzyn7c73e752016-06-06 14:56:00 -07001034
Tom Cherryfb1373a2019-10-29 07:05:24 -07001035 if (err < 0 && errno != ENOENT) {
Mark Salyzyn7c73e752016-06-06 14:56:00 -07001036 perror("while clearing log files");
Tom Cherryfb1373a2019-10-29 07:05:24 -07001037 ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
Mark Salyzyn7c73e752016-06-06 14:56:00 -07001038 }
Mark Salyzyn7c73e752016-06-06 14:56:00 -07001039 }
Tom Cherryfb1373a2019-10-29 07:05:24 -07001040 } else if (android_logger_clear(logger)) {
1041 ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001042 }
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001043 }
1044
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001045 if (setLogSize) {
Tom Cherryfb1373a2019-10-29 07:05:24 -07001046 if (android_logger_set_log_size(logger, setLogSize)) {
1047 ReportErrorName(buffer_name, security_buffer_selected, &set_size_failures);
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001048 }
Mark Salyzync89839a2014-02-11 12:29:31 -08001049 }
1050
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001051 if (getLogSize) {
Tom Cherryfb1373a2019-10-29 07:05:24 -07001052 long size = android_logger_get_log_size(logger);
1053 long readable = android_logger_get_log_readable_size(logger);
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001054
Tom Cherryfb1373a2019-10-29 07:05:24 -07001055 if (size < 0 || readable < 0) {
1056 ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001057 } else {
Wei Wang8b584172018-09-05 11:05:57 -07001058 auto size_format = format_of_size(size);
1059 auto readable_format = format_of_size(readable);
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08001060 std::string str = android::base::StringPrintf(
Tom Cherryfb1373a2019-10-29 07:05:24 -07001061 "%s: ring buffer is %lu %sB (%lu %sB consumed),"
1062 " max entry is %d B, max payload is %d B\n",
1063 buffer_name, size_format.first, size_format.second, readable_format.first,
1064 readable_format.second, (int)LOGGER_ENTRY_MAX_LEN,
1065 (int)LOGGER_ENTRY_MAX_PAYLOAD);
Tom Cherryb1cf4282019-10-24 17:35:26 -07001066 TEMP_FAILURE_RETRY(write(output_fd_.get(), str.data(), str.length()));
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001067 }
Joe Onoratod23b9cf2010-02-26 10:04:23 -08001068 }
The Android Open Source Project190995d2009-03-03 19:32:55 -08001069 }
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08001070
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001071 // report any errors in the above loop and exit
Tom Cherryfb1373a2019-10-29 07:05:24 -07001072 if (!open_device_failures.empty()) {
1073 LogcatPanic(HELP_FALSE, "Unable to open log device%s '%s'\n",
1074 open_device_failures.size() > 1 ? "s" : "",
1075 Join(open_device_failures, ",").c_str());
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001076 }
Tom Cherryfb1373a2019-10-29 07:05:24 -07001077 if (!clear_failures.empty()) {
1078 LogcatPanic(HELP_FALSE, "failed to clear the '%s' log%s\n",
1079 Join(clear_failures, ",").c_str(), clear_failures.size() > 1 ? "s" : "");
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001080 }
Tom Cherryfb1373a2019-10-29 07:05:24 -07001081 if (!set_size_failures.empty()) {
1082 LogcatPanic(HELP_FALSE, "failed to set the '%s' log size%s\n",
1083 Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001084 }
Tom Cherryfb1373a2019-10-29 07:05:24 -07001085 if (!get_size_failures.empty()) {
1086 LogcatPanic(HELP_FALSE, "failed to get the readable '%s' log size%s\n",
1087 Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
Mark Salyzyn7ccdb902015-09-16 15:34:00 -07001088 }
The Android Open Source Project190995d2009-03-03 19:32:55 -08001089
Mark Salyzync89839a2014-02-11 12:29:31 -08001090 if (setPruneList) {
Traian Schiau9f978602015-04-10 15:51:39 +03001091 size_t len = strlen(setPruneList);
Mark Salyzynd8b454f2017-02-10 13:09:07 -08001092 // extra 32 bytes are needed by android_logger_set_prune_list
Traian Schiau9f978602015-04-10 15:51:39 +03001093 size_t bLen = len + 32;
Mark Salyzyne5f043c2017-03-01 08:30:06 -08001094 char* buf = nullptr;
Traian Schiau9f978602015-04-10 15:51:39 +03001095 if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
1096 buf[len] = '\0';
Tom Cherryfb1373a2019-10-29 07:05:24 -07001097 if (android_logger_set_prune_list(logger_list.get(), buf, bLen)) {
Tom Cherryb1cf4282019-10-24 17:35:26 -07001098 LogcatPanic(HELP_FALSE, "failed to set the prune list");
Traian Schiau9f978602015-04-10 15:51:39 +03001099 }
1100 free(buf);
1101 } else {
Tom Cherryb1cf4282019-10-24 17:35:26 -07001102 LogcatPanic(HELP_FALSE, "failed to set the prune list (alloc)");
Mark Salyzync89839a2014-02-11 12:29:31 -08001103 }
Tom Cherryb1cf4282019-10-24 17:35:26 -07001104 return EXIT_SUCCESS;
Mark Salyzync89839a2014-02-11 12:29:31 -08001105 }
1106
Mark Salyzync402bc72014-04-01 17:19:47 -07001107 if (printStatistics || getPruneList) {
Mark Salyzynd774bce2014-02-06 14:48:50 -08001108 size_t len = 8192;
Mark Salyzynd8b454f2017-02-10 13:09:07 -08001109 char* buf;
Mark Salyzynd774bce2014-02-06 14:48:50 -08001110
Mark Salyzynd8b454f2017-02-10 13:09:07 -08001111 for (int retry = 32; (retry >= 0) && ((buf = new char[len]));
Mark Salyzyne5f043c2017-03-01 08:30:06 -08001112 delete[] buf, buf = nullptr, --retry) {
Mark Salyzync89839a2014-02-11 12:29:31 -08001113 if (getPruneList) {
Tom Cherryfb1373a2019-10-29 07:05:24 -07001114 android_logger_get_prune_list(logger_list.get(), buf, len);
Mark Salyzync89839a2014-02-11 12:29:31 -08001115 } else {
Tom Cherryfb1373a2019-10-29 07:05:24 -07001116 android_logger_get_statistics(logger_list.get(), buf, len);
Mark Salyzync89839a2014-02-11 12:29:31 -08001117 }
Mark Salyzynd8b454f2017-02-10 13:09:07 -08001118 buf[len - 1] = '\0';
Traian Schiau9f978602015-04-10 15:51:39 +03001119 if (atol(buf) < 3) {
Mark Salyzynd8b454f2017-02-10 13:09:07 -08001120 delete[] buf;
Mark Salyzyne5f043c2017-03-01 08:30:06 -08001121 buf = nullptr;
Mark Salyzynd774bce2014-02-06 14:48:50 -08001122 break;
1123 }
Traian Schiau9f978602015-04-10 15:51:39 +03001124 size_t ret = atol(buf) + 1;
1125 if (ret <= len) {
1126 len = ret;
Mark Salyzynd774bce2014-02-06 14:48:50 -08001127 break;
1128 }
Traian Schiau9f978602015-04-10 15:51:39 +03001129 len = ret;
Mark Salyzynd774bce2014-02-06 14:48:50 -08001130 }
1131
1132 if (!buf) {
Tom Cherryb1cf4282019-10-24 17:35:26 -07001133 LogcatPanic(HELP_FALSE, "failed to read data");
Mark Salyzynd774bce2014-02-06 14:48:50 -08001134 }
1135
1136 // remove trailing FF
Mark Salyzynd8b454f2017-02-10 13:09:07 -08001137 char* cp = buf + len - 1;
Mark Salyzynd774bce2014-02-06 14:48:50 -08001138 *cp = '\0';
1139 bool truncated = *--cp != '\f';
Mark Salyzyne5f043c2017-03-01 08:30:06 -08001140 if (!truncated) *cp = '\0';
Mark Salyzynd774bce2014-02-06 14:48:50 -08001141
1142 // squash out the byte count
1143 cp = buf;
1144 if (!truncated) {
Mark Salyzyne5f043c2017-03-01 08:30:06 -08001145 while (isdigit(*cp)) ++cp;
1146 if (*cp == '\n') ++cp;
Mark Salyzynd774bce2014-02-06 14:48:50 -08001147 }
1148
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08001149 len = strlen(cp);
Tom Cherryb1cf4282019-10-24 17:35:26 -07001150 TEMP_FAILURE_RETRY(write(output_fd_.get(), cp, len));
Mark Salyzynd8b454f2017-02-10 13:09:07 -08001151 delete[] buf;
Tom Cherryb1cf4282019-10-24 17:35:26 -07001152 return EXIT_SUCCESS;
Mark Salyzynd774bce2014-02-06 14:48:50 -08001153 }
1154
Tom Cherryb1cf4282019-10-24 17:35:26 -07001155 if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
The Android Open Source Project190995d2009-03-03 19:32:55 -08001156
Tom Cherryb1cf4282019-10-24 17:35:26 -07001157 SetupOutputAndSchedulingPolicy(!(mode & ANDROID_LOG_NONBLOCK));
The Android Open Source Project190995d2009-03-03 19:32:55 -08001158
Tom Cherryb1cf4282019-10-24 17:35:26 -07001159 while (!max_count_ || print_count_ < max_count_) {
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001160 struct log_msg log_msg;
Tom Cherryfb1373a2019-10-29 07:05:24 -07001161 int ret = android_logger_list_read(logger_list.get(), &log_msg);
Mark Salyzyne5f043c2017-03-01 08:30:06 -08001162 if (!ret) {
Tom Cherrya59bde42019-11-21 10:31:06 -08001163 LogcatPanic(HELP_FALSE, R"init(read: unexpected EOF!
1164
1165This means that either logd crashed, or more likely, this instance of logcat was unable to read log
1166messages as quickly as they were being produced.
1167
1168If you have enabled significant logging, look into using the -G option to increase log buffer sizes.
1169)init");
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001170 }
1171
1172 if (ret < 0) {
Mark Salyzyne5f043c2017-03-01 08:30:06 -08001173 if (ret == -EAGAIN) break;
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001174
1175 if (ret == -EIO) {
Tom Cherryb1cf4282019-10-24 17:35:26 -07001176 LogcatPanic(HELP_FALSE, "read: unexpected EOF!\n");
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001177 }
1178 if (ret == -EINVAL) {
Tom Cherryb1cf4282019-10-24 17:35:26 -07001179 LogcatPanic(HELP_FALSE, "read: unexpected length.\n");
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001180 }
Tom Cherryb1cf4282019-10-24 17:35:26 -07001181 LogcatPanic(HELP_FALSE, "logcat read failure\n");
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001182 }
1183
Tom Cherryfb1373a2019-10-29 07:05:24 -07001184 if (log_msg.id() > LOG_ID_MAX) {
1185 LogcatPanic(HELP_FALSE, "read: unexpected log id (%d) over LOG_ID_MAX (%d)",
1186 log_msg.id(), LOG_ID_MAX);
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001187 }
1188
Tom Cherryfb1373a2019-10-29 07:05:24 -07001189 PrintDividers(log_msg.id(), printDividers);
1190
Tom Cherryb1cf4282019-10-24 17:35:26 -07001191 if (print_binary_) {
1192 TEMP_FAILURE_RETRY(write(output_fd_.get(), &log_msg, log_msg.len()));
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001193 } else {
Tom Cherryfb1373a2019-10-29 07:05:24 -07001194 ProcessBuffer(&log_msg);
Mark Salyzyn2a8a6aa2013-11-22 10:55:48 -08001195 }
1196 }
Tom Cherryb1cf4282019-10-24 17:35:26 -07001197 return EXIT_SUCCESS;
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08001198}
1199
Tom Cherryd8ea11f2019-10-30 13:51:03 -07001200int main(int argc, char** argv) {
Tom Cherryb1cf4282019-10-24 17:35:26 -07001201 Logcat logcat;
1202 return logcat.Run(argc, argv);
Mark Salyzyn2f1a9a42017-02-10 13:09:07 -08001203}