blob: 6b85f4b323ff21133326aff1b1ff4e9c98108e94 [file] [log] [blame]
Mark Salyzyn5f606602017-02-10 13:09:07 -08001/*
Mark Salyzync0cf90d2017-02-10 13:09:07 -08002 * Copyright (C) 2006-2017 The Android Open Source Project
Mark Salyzyn5f606602017-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 Projectdd7bc332009-03-03 19:32:55 -080016
Mark Salyzyn65772ca2013-12-13 11:10:11 -080017#include <ctype.h>
Mark Salyzynf3555d92015-05-27 07:39:56 -070018#include <dirent.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080019#include <errno.h>
20#include <fcntl.h>
Elliott Hughes61b580e2018-06-15 15:16:20 -070021#include <getopt.h>
Aristidis Papaioannoueba73442014-10-16 22:19:55 -070022#include <math.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070023#include <sched.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070024#include <stdarg.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080025#include <stdio.h>
26#include <stdlib.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080027#include <string.h>
Traian Schiau59763032015-04-10 15:51:39 +030028#include <sys/cdefs.h>
Jaegeuk Kim5327d932019-07-04 18:09:38 -070029#include <sys/ioctl.h>
Riley Andrewsaede9892015-06-08 23:36:34 -070030#include <sys/resource.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080031#include <sys/stat.h>
Mark Salyzynf3555d92015-05-27 07:39:56 -070032#include <sys/types.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070033#include <time.h>
34#include <unistd.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080035
Mark Salyzynf3555d92015-05-27 07:39:56 -070036#include <memory>
Elliott Hughesaddd8522019-08-08 08:53:59 -070037#include <regex>
Mark Salyzynf3555d92015-05-27 07:39:56 -070038#include <string>
Wei Wangc27d4812018-09-05 11:05:57 -070039#include <utility>
Mark Salyzyn1d6928b2017-02-10 13:09:07 -080040#include <vector>
Mark Salyzynf3555d92015-05-27 07:39:56 -070041
Elliott Hughes4f713192015-12-04 22:00:26 -080042#include <android-base/file.h>
Tom Cherryd162f142019-10-24 17:35:26 -070043#include <android-base/macros.h>
Tom Cherry6f061e82019-10-29 07:05:24 -070044#include <android-base/parseint.h>
bohu94aab862017-02-21 14:31:19 -080045#include <android-base/properties.h>
Mark Salyzyn5b1a5382016-08-03 14:20:41 -070046#include <android-base/stringprintf.h>
Elliott Hughes4f713192015-12-04 22:00:26 -080047#include <android-base/strings.h>
Tom Cherryd162f142019-10-24 17:35:26 -070048#include <android-base/unique_fd.h>
Tom Cherry6f061e82019-10-29 07:05:24 -070049#include <android/log.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070050#include <log/event_tag_map.h>
Tom Cherry6f061e82019-10-29 07:05:24 -070051#include <log/log_id.h>
Colin Cross9227bd32013-07-23 16:59:20 -070052#include <log/logprint.h>
Mark Salyzynaeaaf812016-09-30 13:30:33 -070053#include <private/android_logger.h>
Suren Baghdasaryan02843332018-12-21 12:30:16 -080054#include <processgroup/sched_policy.h>
Elliott Hughesb9e53b42016-02-17 11:58:01 -080055#include <system/thread_defs.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080056
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080057#define DEFAULT_MAX_ROTATED_LOGS 4
58
Tom Cherry6f061e82019-10-29 07:05:24 -070059using android::base::Join;
60using android::base::ParseByteCount;
61using android::base::ParseUint;
62using android::base::Split;
Tom Cherryd162f142019-10-24 17:35:26 -070063using android::base::StringPrintf;
64
Tom Cherryd162f142019-10-24 17:35:26 -070065class Logcat {
66 public:
Tom Cherryd162f142019-10-24 17:35:26 -070067 int Run(int argc, char** argv);
Mark Salyzync0cf90d2017-02-10 13:09:07 -080068
Tom Cherryd162f142019-10-24 17:35:26 -070069 private:
70 void RotateLogs();
Tom Cherry6f061e82019-10-29 07:05:24 -070071 void ProcessBuffer(struct log_msg* buf);
72 void PrintDividers(log_id_t log_id, bool print_dividers);
Tom Cherryd162f142019-10-24 17:35:26 -070073 void SetupOutputAndSchedulingPolicy(bool blocking);
74 int SetLogFormat(const char* format_string);
75
Tom Cherry6f061e82019-10-29 07:05:24 -070076 // Used for all options
Tom Cherryd162f142019-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 Cherry6f061e82019-10-29 07:05:24 -070080
81 // For logging to a file and log rotation
Tom Cherryd162f142019-10-24 17:35:26 -070082 const char* output_file_name_ = nullptr;
Tom Cherry6f061e82019-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 Cherryd162f142019-10-24 17:35:26 -070085 size_t out_byte_count_ = 0;
Tom Cherry6f061e82019-10-29 07:05:24 -070086
87 // For binary log buffers
Tom Cherryd162f142019-10-24 17:35:26 -070088 int print_binary_ = 0;
Tom Cherryd162f142019-10-24 17:35:26 -070089 std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
90 nullptr, &android_closeEventTagMap};
Tom Cherryd162f142019-10-24 17:35:26 -070091 bool has_opened_event_tag_map_ = false;
Tom Cherry6f061e82019-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 Salyzync0cf90d2017-02-10 13:09:07 -0800104};
105
Mark Salyzyn5f606602017-02-10 13:09:07 -0800106// logd prefixes records with a length field
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800107#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
108
Mark Salyzyn5f606602017-02-10 13:09:07 -0800109enum helpType { HELP_FALSE, HELP_TRUE, HELP_FORMAT };
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700110
Tom Cherryd162f142019-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 Schiau59763032015-04-10 15:51:39 +0300114
Jaegeuk Kim5327d932019-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 Cherryd162f142019-10-24 17:35:26 -0700121 int fd = open(pathname, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
Jaegeuk Kim5327d932019-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 Projectdd7bc332009-03-03 19:32:55 -0800131}
132
Tom Cherryd162f142019-10-24 17:35:26 -0700133void Logcat::RotateLogs() {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800134 // Can't rotate logs if we're not outputting to a file
Tom Cherryd162f142019-10-24 17:35:26 -0700135 if (!output_file_name_) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800136
Tom Cherryd162f142019-10-24 17:35:26 -0700137 output_fd_.reset();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800138
Mark Salyzyn5f606602017-02-10 13:09:07 -0800139 // Compute the maximum number of digits needed to count up to
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800140 // maxRotatedLogs in decimal. eg:
141 // maxRotatedLogs == 30
Mark Salyzyn5f606602017-02-10 13:09:07 -0800142 // -> log10(30) == 1.477
143 // -> maxRotationCountDigits == 2
Tom Cherryd162f142019-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 Papaioannoueba73442014-10-16 22:19:55 -0700146
Tom Cherryd162f142019-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 Projectdd7bc332009-03-03 19:32:55 -0800150
Mark Salyzyn5b1a5382016-08-03 14:20:41 -0700151 std::string file0;
Mark Salyzynde022a82017-03-01 08:30:06 -0800152 if (!(i - 1)) {
Tom Cherryd162f142019-10-24 17:35:26 -0700153 file0 = output_file_name_;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800154 } else {
Tom Cherryd162f142019-10-24 17:35:26 -0700155 file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800156 }
157
Mark Salyzynde022a82017-03-01 08:30:06 -0800158 if (!file0.length() || !file1.length()) {
Traian Schiau59763032015-04-10 15:51:39 +0300159 perror("while rotating log files");
160 break;
161 }
162
Tom Cherryd162f142019-10-24 17:35:26 -0700163 int err = rename(file0.c_str(), file1.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800164
165 if (err < 0 && errno != ENOENT) {
166 perror("while rotating log files");
167 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800168 }
169
Tom Cherryd162f142019-10-24 17:35:26 -0700170 output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800171
Tom Cherryd162f142019-10-24 17:35:26 -0700172 if (!output_fd_.ok()) {
173 LogcatPanic(HELP_FALSE, "couldn't open output file");
Mark Salyzyne3d0c962017-02-17 13:15:51 -0800174 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800175
Tom Cherryd162f142019-10-24 17:35:26 -0700176 out_byte_count_ = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800177}
178
Tom Cherry6f061e82019-10-29 07:05:24 -0700179void Logcat::ProcessBuffer(struct log_msg* buf) {
Mathias Agopian50844522010-03-17 16:10:26 -0700180 int bytesWritten = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800181 int err;
182 AndroidLogEntry entry;
183 char binaryMsgBuf[1024];
184
Tom Cherry6f061e82019-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 Cherryd162f142019-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 Salyzyn9421b0c2015-02-26 14:33:35 -0800192 }
Tom Cherryd162f142019-10-24 17:35:26 -0700193 err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
Tom Cherry441054a2019-10-15 16:53:11 -0700194 binaryMsgBuf, sizeof(binaryMsgBuf));
Mark Salyzyn5f606602017-02-10 13:09:07 -0800195 // printf(">>> pri=%d len=%d msg='%s'\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800196 // entry.priority, entry.messageLen, entry.message);
197 } else {
Tom Cherry441054a2019-10-15 16:53:11 -0700198 err = android_log_processLogBuffer(&buf->entry, &entry);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800199 }
Tom Cherryd162f142019-10-24 17:35:26 -0700200 if (err < 0 && !debug_) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800201
Tom Cherryd162f142019-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 Onoratoe2bf2ea2010-03-01 09:11:54 -0800206
Tom Cherryd162f142019-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 Dahlin6ac498d2016-03-17 14:04:52 -0700210
Mark Salyzync9202772016-03-30 09:38:31 -0700211 if (bytesWritten < 0) {
Tom Cherryd162f142019-10-24 17:35:26 -0700212 LogcatPanic(HELP_FALSE, "output error");
Mark Salyzync9202772016-03-30 09:38:31 -0700213 }
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800214 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800215 }
216
Tom Cherryd162f142019-10-24 17:35:26 -0700217 out_byte_count_ += bytesWritten;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800218
Tom Cherryd162f142019-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 Projectdd7bc332009-03-03 19:32:55 -0800221 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800222}
223
Tom Cherry6f061e82019-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 Onorato6fa09a02010-02-26 10:04:23 -0800227 }
Tom Cherry6f061e82019-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 Onorato6fa09a02010-02-26 10:04:23 -0800237}
238
Tom Cherryd162f142019-10-24 17:35:26 -0700239void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
240 if (!output_file_name_) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800241
Mark Salyzynad5e4112016-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 Cherryd162f142019-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 Salyzyn3ef730c2015-06-02 07:57:16 -0700247 }
248
Tom Cherryd162f142019-10-24 17:35:26 -0700249 struct sched_param param = {};
Mark Salyzyn5f606602017-02-10 13:09:07 -0800250 if (sched_setscheduler((pid_t)0, SCHED_BATCH, &param) < 0) {
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700251 fprintf(stderr, "failed to set to batch scheduler\n");
252 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800253
Tom Cherryd162f142019-10-24 17:35:26 -0700254 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
255 fprintf(stderr, "failed set to priority\n");
Riley Andrewsaede9892015-06-08 23:36:34 -0700256 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800257 }
Mark Salyzynad5e4112016-08-04 07:53:52 -0700258
Tom Cherryd162f142019-10-24 17:35:26 -0700259 output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
Mark Salyzynad5e4112016-08-04 07:53:52 -0700260
Tom Cherryd162f142019-10-24 17:35:26 -0700261 if (!output_fd_.ok()) {
262 LogcatPanic(HELP_FALSE, "couldn't open output file");
Mark Salyzynad5e4112016-08-04 07:53:52 -0700263 }
264
265 struct stat statbuf;
Tom Cherryd162f142019-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 Salyzynad5e4112016-08-04 07:53:52 -0700269 }
270
Mark Salyzyn5f606602017-02-10 13:09:07 -0800271 if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
Tom Cherryd162f142019-10-24 17:35:26 -0700272 output_fd_.reset();
273 LogcatPanic(HELP_FALSE, "invalid output file stat\n");
Mark Salyzynad5e4112016-08-04 07:53:52 -0700274 }
275
Tom Cherryd162f142019-10-24 17:35:26 -0700276 out_byte_count_ = statbuf.st_size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800277}
278
Mark Salyzyn5f606602017-02-10 13:09:07 -0800279// clang-format off
Tom Cherryd162f142019-10-24 17:35:26 -0700280static void show_help() {
281 const char* cmd = getprogname();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800282
Tom Cherryd162f142019-10-24 17:35:26 -0700283 fprintf(stderr, "Usage: %s [options] [filterspecs]\n", cmd);
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800284
Tom Cherry41697322019-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 Projectdd7bc332009-03-03 19:32:55 -0800357
Tom Cherryd162f142019-10-24 17:35:26 -0700358 fprintf(stderr, "\nfilterspecs are a series of \n"
The Android Open Source Projectdd7bc332009-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 Salyzynbba894a2015-03-09 09:32:56 -0700361 " V Verbose (default for <tag>)\n"
362 " D Debug (default for '*')\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800363 " I Info\n"
364 " W Warn\n"
365 " E Error\n"
366 " F Fatal\n"
Mark Salyzynbba894a2015-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 Salyzyn649fc602014-09-16 09:15:15 -0700373 "or defaults to \"threadtime\"\n\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800374}
375
Tom Cherryd162f142019-10-24 17:35:26 -0700376static void show_format_help() {
377 fprintf(stderr,
Mark Salyzyn4fd05072016-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 Salyzync74f8d92017-05-15 13:40:33 -0700389 " thread — Display priority, PID and TID of process issuing the message.\n"
Mark Salyzyn4fd05072016-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 Salyzyn5f606602017-02-10 13:09:07 -0800409// clang-format on
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700410
Tom Cherryd162f142019-10-24 17:35:26 -0700411int Logcat::SetLogFormat(const char* format_string) {
412 AndroidLogPrintFormat format = android_log_formatFromString(format_string);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800413
Mark Salyzynde022a82017-03-01 08:30:06 -0800414 // invalid string?
415 if (format == FORMAT_OFF) return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800416
Tom Cherryd162f142019-10-24 17:35:26 -0700417 return android_log_setPrintFormat(logformat_.get(), format);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800418}
419
Wei Wangc27d4812018-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 Salyzyn671e3432014-05-06 07:34:59 -0700423 for (i = 0;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800424 (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
425 value /= 1024, ++i)
426 ;
Wei Wangc27d4812018-09-05 11:05:57 -0700427 return std::make_pair(value, multipliers[i]);
Mark Salyzyn671e3432014-05-06 07:34:59 -0700428}
429
Tom Cherryd162f142019-10-24 17:35:26 -0700430static void LogcatPanic(enum helpType showHelp, const char* fmt, ...) {
Mark Salyzyn5f606602017-02-10 13:09:07 -0800431 va_list args;
Mark Salyzyn77d7e812015-04-13 09:27:57 -0700432 va_start(args, fmt);
Tom Cherryd162f142019-10-24 17:35:26 -0700433 vfprintf(stderr, fmt, args);
Mark Salyzyn77d7e812015-04-13 09:27:57 -0700434 va_end(args);
Traian Schiau59763032015-04-10 15:51:39 +0300435
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700436 switch (showHelp) {
Mark Salyzyn5f606602017-02-10 13:09:07 -0800437 case HELP_TRUE:
Tom Cherryd162f142019-10-24 17:35:26 -0700438 show_help();
Mark Salyzyn5f606602017-02-10 13:09:07 -0800439 break;
440 case HELP_FORMAT:
Tom Cherryd162f142019-10-24 17:35:26 -0700441 show_format_help();
Mark Salyzyn5f606602017-02-10 13:09:07 -0800442 break;
443 case HELP_FALSE:
444 default:
445 break;
Traian Schiau59763032015-04-10 15:51:39 +0300446 }
447
Tom Cherryd162f142019-10-24 17:35:26 -0700448 exit(EXIT_FAILURE);
Traian Schiau59763032015-04-10 15:51:39 +0300449}
450
Mark Salyzyn5f606602017-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 Salyzynde022a82017-03-01 08:30:06 -0800453 if (ep) return ep;
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700454 ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
Mark Salyzynde022a82017-03-01 08:30:06 -0800455 if (ep) return ep;
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700456 return t.strptime(cp, "%s.%q");
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700457}
Mark Salyzynf3555d92015-05-27 07:39:56 -0700458
Mark Salyzyn31961062016-08-04 07:43:46 -0700459// Find last logged line in <outputFileName>, or <outputFileName>.1
Mark Salyzyne9ade172017-03-02 15:09:41 -0800460static log_time lastLogTime(const char* outputFileName) {
Mark Salyzynf3555d92015-05-27 07:39:56 -0700461 log_time retval(log_time::EPOCH);
Mark Salyzynde022a82017-03-01 08:30:06 -0800462 if (!outputFileName) return retval;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700463
Mark Salyzynf3555d92015-05-27 07:39:56 -0700464 std::string directory;
Mark Salyzyne9ade172017-03-02 15:09:41 -0800465 const char* file = strrchr(outputFileName, '/');
Mark Salyzynf3555d92015-05-27 07:39:56 -0700466 if (!file) {
467 directory = ".";
468 file = outputFileName;
469 } else {
Mark Salyzyne9ade172017-03-02 15:09:41 -0800470 directory = std::string(outputFileName, file - outputFileName);
Mark Salyzynf3555d92015-05-27 07:39:56 -0700471 ++file;
472 }
Mark Salyzync18c2132016-04-01 07:52:20 -0700473
Mark Salyzyn5f606602017-02-10 13:09:07 -0800474 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()),
475 closedir);
Mark Salyzynde022a82017-03-01 08:30:06 -0800476 if (!dir.get()) return retval;
Mark Salyzync18c2132016-04-01 07:52:20 -0700477
Mark Salyzyn31961062016-08-04 07:43:46 -0700478 log_time now(android_log_clockid());
Mark Salyzync18c2132016-04-01 07:52:20 -0700479
Mark Salyzynf3555d92015-05-27 07:39:56 -0700480 size_t len = strlen(file);
481 log_time modulo(0, NS_PER_SEC);
Mark Salyzyn5f606602017-02-10 13:09:07 -0800482 struct dirent* dp;
Mark Salyzync18c2132016-04-01 07:52:20 -0700483
Mark Salyzynde022a82017-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 Salyzyn5f606602017-02-10 13:09:07 -0800486 (dp->d_name[len] && ((dp->d_name[len] != '.') ||
Mark Salyzynde022a82017-03-01 08:30:06 -0800487 (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) {
Mark Salyzynf3555d92015-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 Salyzynde022a82017-03-01 08:30:06 -0800495 if (!android::base::ReadFileToString(file_name, &file)) continue;
Mark Salyzynf3555d92015-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 Salyzyn5f606602017-02-10 13:09:07 -0800500 char* ep = parseTime(t, line.c_str());
Mark Salyzynde022a82017-03-01 08:30:06 -0800501 if (!ep || (*ep != ' ')) continue;
Mark Salyzynf3555d92015-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 Salyzynde022a82017-03-01 08:30:06 -0800519 if (!dp->d_name[len] && found) break;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700520 }
Mark Salyzynde022a82017-03-01 08:30:06 -0800521 if (retval == log_time::EPOCH) return retval;
Mark Salyzynf3555d92015-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 Cherry6f061e82019-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 Salyzyn26a1fac2017-01-20 14:07:29 -0800532 }
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800533}
Traian Schiau59763032015-04-10 15:51:39 +0300534
Tom Cherryd162f142019-10-24 17:35:26 -0700535int Logcat::Run(int argc, char** argv) {
Mark Salyzynb45a1752017-02-28 09:20:31 -0800536 bool hasSetLogFormat = false;
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800537 bool clearLog = false;
Tom Cherry6f061e82019-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 Salyzyn26a1fac2017-01-20 14:07:29 -0800540 bool getLogSize = false;
541 bool getPruneList = false;
542 bool printStatistics = false;
543 bool printDividers = false;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800544 unsigned long setLogSize = 0;
Mark Salyzyne9ade172017-03-02 15:09:41 -0800545 const char* setPruneList = nullptr;
546 const char* setId = nullptr;
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800547 int mode = ANDROID_LOG_RDONLY;
Mark Salyzynf3290292017-02-10 13:09:07 -0800548 std::string forceFilters;
Traian Schiau59763032015-04-10 15:51:39 +0300549 size_t tail_lines = 0;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800550 log_time tail_time(log_time::EPOCH);
Kristian Monsen562e5132015-06-05 14:10:12 -0700551 size_t pid = 0;
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700552 bool got_t = false;
Tom Cherry6f061e82019-10-29 07:05:24 -0700553 unsigned id_mask = 0;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800554
Mark Salyzynde022a82017-03-01 08:30:06 -0800555 if (argc == 2 && !strcmp(argv[1], "--help")) {
Tom Cherryd162f142019-10-24 17:35:26 -0700556 show_help();
557 return EXIT_SUCCESS;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800558 }
559
Mark Salyzynb45a1752017-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 Hughes61b580e2018-06-15 15:16:20 -0700564 optind = 0;
565 while (true) {
Kristian Monsen562e5132015-06-05 14:10:12 -0700566 int option_index = 0;
Mark Salyzync9202772016-03-30 09:38:31 -0700567 // list of long-argument only strings for later comparison
Kristian Monsen562e5132015-06-05 14:10:12 -0700568 static const char pid_str[] = "pid";
Mark Salyzyn538bc122016-11-16 15:28:31 -0800569 static const char debug_str[] = "debug";
Mark Salyzyn02687e72016-08-03 14:20:41 -0700570 static const char id_str[] = "id";
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800571 static const char wrap_str[] = "wrap";
Mark Salyzync9202772016-03-30 09:38:31 -0700572 static const char print_str[] = "print";
Mark Salyzyn5f606602017-02-10 13:09:07 -0800573 // clang-format off
Kristian Monsen562e5132015-06-05 14:10:12 -0700574 static const struct option long_options[] = {
Mark Salyzynde022a82017-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 Salyzync18c2132016-04-01 07:52:20 -0700583 // hidden and undocumented reserved alias for --regex
Mark Salyzynde022a82017-03-01 08:30:06 -0800584 { "grep", required_argument, nullptr, 'e' },
Mark Salyzynd85f6462016-03-30 09:15:09 -0700585 // hidden and undocumented reserved alias for --max-count
Mark Salyzynde022a82017-03-01 08:30:06 -0800586 { "head", required_argument, nullptr, 'm' },
Mark Salyzyne74e51d2017-04-03 09:30:20 -0700587 { "help", no_argument, nullptr, 'h' },
Mark Salyzynde022a82017-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 Salyzynd85f6462016-03-30 09:15:09 -0700598 // hidden and undocumented reserved alias for -t
Mark Salyzynde022a82017-03-01 08:30:06 -0800599 { "tail", required_argument, nullptr, 't' },
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800600 // support, but ignore and do not document, the optional argument
Mark Salyzynde022a82017-03-01 08:30:06 -0800601 { wrap_str, optional_argument, nullptr, 0 },
602 { nullptr, 0, nullptr, 0 }
Kristian Monsen562e5132015-06-05 14:10:12 -0700603 };
Mark Salyzyn5f606602017-02-10 13:09:07 -0800604 // clang-format on
Kristian Monsen562e5132015-06-05 14:10:12 -0700605
Elliott Hughes61b580e2018-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 Projectdd7bc332009-03-03 19:32:55 -0800609
Elliott Hughes61b580e2018-06-15 15:16:20 -0700610 switch (c) {
Kristian Monsen562e5132015-06-05 14:10:12 -0700611 case 0:
Mark Salyzyn02687e72016-08-03 14:20:41 -0700612 // only long options
Kristian Monsen562e5132015-06-05 14:10:12 -0700613 if (long_options[option_index].name == pid_str) {
Steven Morelandb0e867a2019-08-02 10:13:57 -0700614 if (pid != 0) {
Tom Cherryd162f142019-10-24 17:35:26 -0700615 LogcatPanic(HELP_TRUE, "Only supports one PID argument.\n");
Steven Morelandb0e867a2019-08-02 10:13:57 -0700616 }
617
Kristian Monsen562e5132015-06-05 14:10:12 -0700618 // ToDo: determine runtime PID_MAX?
Tom Cherry6f061e82019-10-29 07:05:24 -0700619 if (!ParseUint(optarg, &pid) || pid < 1) {
Tom Cherryd162f142019-10-24 17:35:26 -0700620 LogcatPanic(HELP_TRUE, "%s %s out of range\n",
621 long_options[option_index].name, optarg);
Kristian Monsen562e5132015-06-05 14:10:12 -0700622 }
623 break;
624 }
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800625 if (long_options[option_index].name == wrap_str) {
Mark Salyzyn5f606602017-02-10 13:09:07 -0800626 mode |= ANDROID_LOG_WRAP | ANDROID_LOG_RDONLY |
Mark Salyzyn41ba25f2015-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 Cherry6f061e82019-10-29 07:05:24 -0700630 if (optarg && (!ParseUint(optarg, &dummy) || dummy < 1)) {
Tom Cherryd162f142019-10-24 17:35:26 -0700631 LogcatPanic(HELP_TRUE, "%s %s out of range\n",
632 long_options[option_index].name, optarg);
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800633 }
Tom Cherryd162f142019-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 Salyzyn41ba25f2015-11-30 13:48:56 -0800638 }
639 break;
640 }
Mark Salyzync9202772016-03-30 09:38:31 -0700641 if (long_options[option_index].name == print_str) {
Tom Cherryd162f142019-10-24 17:35:26 -0700642 print_it_anyways_ = true;
Mark Salyzync9202772016-03-30 09:38:31 -0700643 break;
644 }
Mark Salyzyn538bc122016-11-16 15:28:31 -0800645 if (long_options[option_index].name == debug_str) {
Tom Cherryd162f142019-10-24 17:35:26 -0700646 debug_ = true;
Mark Salyzyn538bc122016-11-16 15:28:31 -0800647 break;
648 }
Mark Salyzyn02687e72016-08-03 14:20:41 -0700649 if (long_options[option_index].name == id_str) {
Elliott Hughes61b580e2018-06-15 15:16:20 -0700650 setId = (optarg && optarg[0]) ? optarg : nullptr;
Mark Salyzyn02687e72016-08-03 14:20:41 -0700651 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800652 break;
Kristian Monsen562e5132015-06-05 14:10:12 -0700653
Mark Salyzyn95132e92013-11-22 10:55:48 -0800654 case 's':
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800655 // default to all silent
Tom Cherryd162f142019-10-24 17:35:26 -0700656 android_log_addFilterRule(logformat_.get(), "*:s");
Mark Salyzyn5f606602017-02-10 13:09:07 -0800657 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800658
659 case 'c':
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800660 clearLog = true;
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800661 mode |= ANDROID_LOG_WRONLY;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800662 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800663
Mark Salyzyn7c975ac2014-12-15 10:01:31 -0800664 case 'L':
Mark Salyzyn5f606602017-02-10 13:09:07 -0800665 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE |
666 ANDROID_LOG_NONBLOCK;
667 break;
Mark Salyzyn7c975ac2014-12-15 10:01:31 -0800668
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800669 case 'd':
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800670 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800671 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800672
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800673 case 't':
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700674 got_t = true;
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800675 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
Chih-Hung Hsieh502f4862018-09-13 11:08:41 -0700676 FALLTHROUGH_INTENDED;
Mark Salyzyn5d3d1f12013-12-09 13:47:00 -0800677 case 'T':
Elliott Hughes61b580e2018-06-15 15:16:20 -0700678 if (strspn(optarg, "0123456789") != strlen(optarg)) {
679 char* cp = parseTime(tail_time, optarg);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800680 if (!cp) {
Tom Cherryd162f142019-10-24 17:35:26 -0700681 LogcatPanic(HELP_FALSE, "-%c \"%s\" not in time format\n", c, optarg);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800682 }
683 if (*cp) {
Elliott Hughes61b580e2018-06-15 15:16:20 -0700684 char ch = *cp;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800685 *cp = '\0';
Tom Cherryd162f142019-10-24 17:35:26 -0700686 fprintf(stderr, "WARNING: -%c \"%s\"\"%c%s\" time truncated\n", c, optarg,
687 ch, cp + 1);
Elliott Hughes61b580e2018-06-15 15:16:20 -0700688 *cp = ch;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800689 }
690 } else {
Tom Cherry6f061e82019-10-29 07:05:24 -0700691 if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
Tom Cherryd162f142019-10-24 17:35:26 -0700692 fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800693 tail_lines = 1;
694 }
695 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800696 break;
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800697
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800698 case 'D':
699 printDividers = true;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800700 break;
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800701
Casey Dahlindc42a872016-03-17 16:18:55 -0700702 case 'e':
Tom Cherryd162f142019-10-24 17:35:26 -0700703 regex_.reset(new std::regex(optarg));
Mark Salyzyn5f606602017-02-10 13:09:07 -0800704 break;
Casey Dahlindc42a872016-03-17 16:18:55 -0700705
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700706 case 'm': {
Tom Cherry6f061e82019-10-29 07:05:24 -0700707 if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
Tom Cherryd162f142019-10-24 17:35:26 -0700708 LogcatPanic(HELP_FALSE, "-%c \"%s\" isn't an integer greater than zero\n", c,
709 optarg);
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700710 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800711 } break;
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700712
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800713 case 'g':
Elliott Hughes61b580e2018-06-15 15:16:20 -0700714 if (!optarg) {
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800715 getLogSize = true;
Mark Salyzynf8bff872015-11-30 12:57:56 -0800716 break;
717 }
Chih-Hung Hsieh502f4862018-09-13 11:08:41 -0700718 FALLTHROUGH_INTENDED;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800719
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800720 case 'G': {
Tom Cherry6f061e82019-10-29 07:05:24 -0700721 if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
Tom Cherryd162f142019-10-24 17:35:26 -0700722 LogcatPanic(HELP_FALSE, "ERROR: -G <num><multiplier>\n");
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800723 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800724 } break;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800725
726 case 'p':
Elliott Hughes61b580e2018-06-15 15:16:20 -0700727 if (!optarg) {
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800728 getPruneList = true;
Mark Salyzynf8bff872015-11-30 12:57:56 -0800729 break;
730 }
Chih-Hung Hsieh502f4862018-09-13 11:08:41 -0700731 FALLTHROUGH_INTENDED;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800732
733 case 'P':
Elliott Hughes61b580e2018-06-15 15:16:20 -0700734 setPruneList = optarg;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800735 break;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800736
Tom Cherry6f061e82019-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 Salyzyn45177732016-04-11 14:03:48 -0700743 } else {
Tom Cherry6f061e82019-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 Salyzyn34facab2014-02-06 14:48:50 -0800747 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700748 if (log_id == LOG_ID_SECURITY) {
749 security_buffer_selected = true;
Mark Salyzyn083b0372015-12-04 10:59:45 -0800750 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700751 id_mask |= (1 << log_id);
Joe Onorato6fa09a02010-02-26 10:04:23 -0800752 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800753 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700754 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800755
756 case 'B':
Tom Cherryd162f142019-10-24 17:35:26 -0700757 print_binary_ = 1;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800758 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800759
760 case 'f':
Mark Salyzynde022a82017-03-01 08:30:06 -0800761 if ((tail_time == log_time::EPOCH) && !tail_lines) {
Elliott Hughes61b580e2018-06-15 15:16:20 -0700762 tail_time = lastLogTime(optarg);
Mark Salyzynf3555d92015-05-27 07:39:56 -0700763 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800764 // redirect output to a file
Tom Cherryd162f142019-10-24 17:35:26 -0700765 output_file_name_ = optarg;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800766 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800767
Mark Salyzyn1325ebf2016-06-07 13:03:10 -0700768 case 'r':
Tom Cherry6f061e82019-10-29 07:05:24 -0700769 if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
Tom Cherryd162f142019-10-24 17:35:26 -0700770 LogcatPanic(HELP_TRUE, "Invalid parameter \"%s\" to -r\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800771 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800772 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800773
Mark Salyzyn1325ebf2016-06-07 13:03:10 -0700774 case 'n':
Tom Cherry6f061e82019-10-29 07:05:24 -0700775 if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
Tom Cherryd162f142019-10-24 17:35:26 -0700776 LogcatPanic(HELP_TRUE, "Invalid parameter \"%s\" to -n\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800777 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800778 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800779
Tom Cherry6f061e82019-10-29 07:05:24 -0700780 case 'v':
Elliott Hughes61b580e2018-06-15 15:16:20 -0700781 if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
Tom Cherryd162f142019-10-24 17:35:26 -0700782 show_format_help();
783 return EXIT_SUCCESS;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700784 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700785 for (const auto& arg : Split(optarg, delimiters)) {
786 int err = SetLogFormat(arg.c_str());
Mark Salyzynb45a1752017-02-28 09:20:31 -0800787 if (err < 0) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700788 LogcatPanic(HELP_FORMAT, "Invalid parameter \"%s\" to -v\n", arg.c_str());
Mark Salyzynb45a1752017-02-28 09:20:31 -0800789 }
Mark Salyzynb45a1752017-02-28 09:20:31 -0800790 if (err) hasSetLogFormat = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800791 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700792 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800793
794 case 'Q':
bohu94aab862017-02-21 14:31:19 -0800795#define LOGCAT_FILTER "androidboot.logcat="
796#define CONSOLE_PIPE_OPTION "androidboot.consolepipe="
Mark Salyzyn5f606602017-02-10 13:09:07 -0800797#define CONSOLE_OPTION "androidboot.console="
bohu94aab862017-02-21 14:31:19 -0800798#define QEMU_PROPERTY "ro.kernel.qemu"
799#define QEMU_CMDLINE "qemu.cmdline"
Mark Salyzyn5f606602017-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
bohu94aab862017-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 Projectdd7bc332009-03-03 19:32:55 -0800807 {
bohu94aab862017-02-21 14:31:19 -0800808 // if not in emulator, exit quietly
809 if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) {
Tom Cherryd162f142019-10-24 17:35:26 -0700810 return EXIT_SUCCESS;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800811 }
Mark Salyzynf3290292017-02-10 13:09:07 -0800812
bohu94aab862017-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 Cherryd162f142019-10-24 17:35:26 -0700821 return EXIT_SUCCESS;
bohu94aab862017-02-21 14:31:19 -0800822 }
823
824 const char* p = logcatFilter + strlen(LOGCAT_FILTER);
Mark Salyzynf3290292017-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 Projectdd7bc332009-03-03 19:32:55 -0800828
bohu94aab862017-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 Salyzynf3290292017-02-10 13:09:07 -0800832 const char* console =
833 strstr(cmdline.c_str(), CONSOLE_OPTION);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800834
bohu94aab862017-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 Cherryd162f142019-10-24 17:35:26 -0700840 return EXIT_FAILURE;
bohu94aab862017-02-21 14:31:19 -0800841 }
842
Mark Salyzynf3290292017-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);
bohu94aab862017-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 Hsiehe5d975c2017-08-03 13:56:49 -0700851 size_t pos = devname.find(',');
bohu94aab862017-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 Projectdd7bc332009-03-03 19:32:55 -0800857
Tom Cherryd162f142019-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 Salyzync0cf90d2017-02-10 13:09:07 -0800863 }
Mark Salyzynf3290292017-02-10 13:09:07 -0800864
bohu94aab862017-02-21 14:31:19 -0800865 if (consolePipe) {
866 // need the trailing '\0'
Tom Cherryd162f142019-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;
bohu94aab862017-02-21 14:31:19 -0800871 }
872 }
Mark Salyzynf3290292017-02-10 13:09:07 -0800873 // close output and error channels, replace with console
Erwin Jansen4f138b22019-11-27 12:58:58 -0800874 dup2(fd, output_fd_.get());
Tom Cherryd162f142019-10-24 17:35:26 -0700875 dup2(fd, STDERR_FILENO);
876 close(fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800877 }
878 break;
879
Mark Salyzyn34facab2014-02-06 14:48:50 -0800880 case 'S':
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800881 printStatistics = true;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800882 break;
883
Traian Schiau59763032015-04-10 15:51:39 +0300884 case ':':
Tom Cherryd162f142019-10-24 17:35:26 -0700885 LogcatPanic(HELP_TRUE, "Option -%c needs an argument\n", optopt);
Traian Schiau59763032015-04-10 15:51:39 +0300886
Mark Salyzyne74e51d2017-04-03 09:30:20 -0700887 case 'h':
Tom Cherryd162f142019-10-24 17:35:26 -0700888 show_help();
889 show_format_help();
890 return EXIT_SUCCESS;
Mark Salyzyne74e51d2017-04-03 09:30:20 -0700891
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800892 default:
Tom Cherryd162f142019-10-24 17:35:26 -0700893 LogcatPanic(HELP_TRUE, "Unrecognized Option %c\n", optopt);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800894 }
895 }
896
Tom Cherryd162f142019-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 Dahlin6ac498d2016-03-17 14:04:52 -0700899 }
Tom Cherryd162f142019-10-24 17:35:26 -0700900 if (print_it_anyways_ && (!regex_ || !max_count_)) {
Mark Salyzync9202772016-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 Cherryd162f142019-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 Salyzync9202772016-03-30 09:38:31 -0700909 }
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700910
Tom Cherry6f061e82019-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 Onorato6fa09a02010-02-26 10:04:23 -0800915 }
916
Tom Cherryd162f142019-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 Projectdd7bc332009-03-03 19:32:55 -0800919 }
920
Tom Cherryd162f142019-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 Salyzyn02687e72016-08-03 14:20:41 -0700924 }
925
Tom Cherryd162f142019-10-24 17:35:26 -0700926 std::string file_name = StringPrintf("%s.id", output_file_name_);
Mark Salyzyn02687e72016-08-03 14:20:41 -0700927 std::string file;
928 bool file_ok = android::base::ReadFileToString(file_name, &file);
Mark Salyzyn5f606602017-02-10 13:09:07 -0800929 android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
930 getuid(), getgid());
Mark Salyzynde022a82017-03-01 08:30:06 -0800931 if (!file_ok || !file.compare(setId)) setId = nullptr;
Mark Salyzyn02687e72016-08-03 14:20:41 -0700932 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800933
Mark Salyzynde022a82017-03-01 08:30:06 -0800934 if (!hasSetLogFormat) {
Tom Cherryd162f142019-10-24 17:35:26 -0700935 const char* logFormat = getenv("ANDROID_PRINTF_LOG");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800936
Mark Salyzynde022a82017-03-01 08:30:06 -0800937 if (!!logFormat) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700938 for (const auto& arg : Split(logFormat, delimiters)) {
939 int err = SetLogFormat(arg.c_str());
Mark Salyzynb45a1752017-02-28 09:20:31 -0800940 // environment should not cause crash of logcat
Tom Cherryd162f142019-10-24 17:35:26 -0700941 if (err < 0) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700942 fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
Mark Salyzynb45a1752017-02-28 09:20:31 -0800943 }
Mark Salyzynb45a1752017-02-28 09:20:31 -0800944 if (err > 0) hasSetLogFormat = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800945 }
Mark Salyzynb45a1752017-02-28 09:20:31 -0800946 }
947 if (!hasSetLogFormat) {
Tom Cherryd162f142019-10-24 17:35:26 -0700948 SetLogFormat("threadtime");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800949 }
950 }
951
Mark Salyzynf3290292017-02-10 13:09:07 -0800952 if (forceFilters.size()) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700953 int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800954 if (err < 0) {
Tom Cherryd162f142019-10-24 17:35:26 -0700955 LogcatPanic(HELP_FALSE, "Invalid filter expression in logcat args\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800956 }
Elliott Hughes61b580e2018-06-15 15:16:20 -0700957 } else if (argc == optind) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800958 // Add from environment variable
Tom Cherryd162f142019-10-24 17:35:26 -0700959 const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800960
Mark Salyzynde022a82017-03-01 08:30:06 -0800961 if (!!env_tags_orig) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700962 int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800963
Mark Salyzyn95132e92013-11-22 10:55:48 -0800964 if (err < 0) {
Tom Cherryd162f142019-10-24 17:35:26 -0700965 LogcatPanic(HELP_TRUE, "Invalid filter expression in ANDROID_LOG_TAGS\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800966 }
967 }
968 } else {
969 // Add from commandline
Elliott Hughes61b580e2018-06-15 15:16:20 -0700970 for (int i = optind ; i < argc ; i++) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700971 int err = android_log_addFilterString(logformat_.get(), argv[i]);
Mark Salyzyn95132e92013-11-22 10:55:48 -0800972 if (err < 0) {
Tom Cherryd162f142019-10-24 17:35:26 -0700973 LogcatPanic(HELP_TRUE, "Invalid filter expression '%s'\n", argv[i]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800974 }
975 }
976 }
977
Tom Cherry9156c532019-11-14 08:56:39 -0800978 if (mode & ANDROID_LOG_PSTORE) {
Tom Cherryc30a3ee2019-12-04 14:37:38 -0800979 if (output_file_name_) {
980 LogcatPanic(HELP_FALSE, "-c is ambiguous with both -f and -L specified.\n");
981 }
982 if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
983 LogcatPanic(HELP_TRUE, "-L is incompatible with -g/-G, -S, and -p/-P\n");
984 }
Tom Cherry9156c532019-11-14 08:56:39 -0800985 if (clearLog) {
986 unlink("/sys/fs/pstore/pmsg-ramoops-0");
987 return EXIT_SUCCESS;
988 }
Tom Cherryc30a3ee2019-12-04 14:37:38 -0800989 }
990
991 if (output_file_name_) {
Tom Cherry9156c532019-11-14 08:56:39 -0800992 if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
Tom Cherryc30a3ee2019-12-04 14:37:38 -0800993 LogcatPanic(HELP_TRUE, "-f is incompatible with -g/-G, -S, and -p/-P\n");
994 }
995
996 if (clearLog || setId) {
997 int max_rotation_count_digits =
998 max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
999
1000 for (int i = max_rotated_logs_; i >= 0; --i) {
1001 std::string file;
1002
1003 if (!i) {
1004 file = output_file_name_;
1005 } else {
1006 file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
1007 }
1008
1009 int err = unlink(file.c_str());
1010
1011 if (err < 0 && errno != ENOENT) {
1012 fprintf(stderr, "failed to delete log file '%s': %s\n", file.c_str(),
1013 strerror(errno));
1014 }
1015 }
1016 }
1017
1018 if (clearLog) {
1019 return EXIT_SUCCESS;
Tom Cherry9156c532019-11-14 08:56:39 -08001020 }
1021 }
1022
Tom Cherry6f061e82019-10-29 07:05:24 -07001023 std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
1024 nullptr, &android_logger_list_free};
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001025 if (tail_time != log_time::EPOCH) {
Tom Cherry6f061e82019-10-29 07:05:24 -07001026 logger_list.reset(android_logger_list_alloc_time(mode, tail_time, pid));
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001027 } else {
Tom Cherry6f061e82019-10-29 07:05:24 -07001028 logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001029 }
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001030 // We have three orthogonal actions below to clear, set log size and
1031 // get log size. All sharing the same iteration loop.
Tom Cherry6f061e82019-10-29 07:05:24 -07001032 std::vector<std::string> open_device_failures;
1033 std::vector<std::string> clear_failures;
1034 std::vector<std::string> set_size_failures;
1035 std::vector<std::string> get_size_failures;
1036
1037 for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
1038 if (!(id_mask & (1 << i))) continue;
1039 const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
1040
1041 auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
1042 if (logger == nullptr) {
1043 ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001044 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001045 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001046
Tom Cherryc30a3ee2019-12-04 14:37:38 -08001047 if (clearLog) {
1048 if (android_logger_clear(logger)) {
Tom Cherry6f061e82019-10-29 07:05:24 -07001049 ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
Joe Onorato6fa09a02010-02-26 10:04:23 -08001050 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001051 }
1052
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001053 if (setLogSize) {
Tom Cherry6f061e82019-10-29 07:05:24 -07001054 if (android_logger_set_log_size(logger, setLogSize)) {
1055 ReportErrorName(buffer_name, security_buffer_selected, &set_size_failures);
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001056 }
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001057 }
1058
Joe Onorato6fa09a02010-02-26 10:04:23 -08001059 if (getLogSize) {
Tom Cherry6f061e82019-10-29 07:05:24 -07001060 long size = android_logger_get_log_size(logger);
1061 long readable = android_logger_get_log_readable_size(logger);
Joe Onorato6fa09a02010-02-26 10:04:23 -08001062
Tom Cherry6f061e82019-10-29 07:05:24 -07001063 if (size < 0 || readable < 0) {
1064 ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001065 } else {
Wei Wangc27d4812018-09-05 11:05:57 -07001066 auto size_format = format_of_size(size);
1067 auto readable_format = format_of_size(readable);
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001068 std::string str = android::base::StringPrintf(
Tom Cherry6f061e82019-10-29 07:05:24 -07001069 "%s: ring buffer is %lu %sB (%lu %sB consumed),"
1070 " max entry is %d B, max payload is %d B\n",
1071 buffer_name, size_format.first, size_format.second, readable_format.first,
1072 readable_format.second, (int)LOGGER_ENTRY_MAX_LEN,
1073 (int)LOGGER_ENTRY_MAX_PAYLOAD);
Tom Cherryd162f142019-10-24 17:35:26 -07001074 TEMP_FAILURE_RETRY(write(output_fd_.get(), str.data(), str.length()));
Joe Onorato6fa09a02010-02-26 10:04:23 -08001075 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001076 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001077 }
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001078
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001079 // report any errors in the above loop and exit
Tom Cherry6f061e82019-10-29 07:05:24 -07001080 if (!open_device_failures.empty()) {
1081 LogcatPanic(HELP_FALSE, "Unable to open log device%s '%s'\n",
1082 open_device_failures.size() > 1 ? "s" : "",
1083 Join(open_device_failures, ",").c_str());
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001084 }
Tom Cherry6f061e82019-10-29 07:05:24 -07001085 if (!clear_failures.empty()) {
1086 LogcatPanic(HELP_FALSE, "failed to clear the '%s' log%s\n",
1087 Join(clear_failures, ",").c_str(), clear_failures.size() > 1 ? "s" : "");
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001088 }
Tom Cherry6f061e82019-10-29 07:05:24 -07001089 if (!set_size_failures.empty()) {
1090 LogcatPanic(HELP_FALSE, "failed to set the '%s' log size%s\n",
1091 Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001092 }
Tom Cherry6f061e82019-10-29 07:05:24 -07001093 if (!get_size_failures.empty()) {
1094 LogcatPanic(HELP_FALSE, "failed to get the readable '%s' log size%s\n",
1095 Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001096 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001097
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001098 if (setPruneList) {
Traian Schiau59763032015-04-10 15:51:39 +03001099 size_t len = strlen(setPruneList);
Mark Salyzyn5f606602017-02-10 13:09:07 -08001100 // extra 32 bytes are needed by android_logger_set_prune_list
Traian Schiau59763032015-04-10 15:51:39 +03001101 size_t bLen = len + 32;
Mark Salyzynde022a82017-03-01 08:30:06 -08001102 char* buf = nullptr;
Traian Schiau59763032015-04-10 15:51:39 +03001103 if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
1104 buf[len] = '\0';
Tom Cherry6f061e82019-10-29 07:05:24 -07001105 if (android_logger_set_prune_list(logger_list.get(), buf, bLen)) {
Tom Cherryd162f142019-10-24 17:35:26 -07001106 LogcatPanic(HELP_FALSE, "failed to set the prune list");
Traian Schiau59763032015-04-10 15:51:39 +03001107 }
1108 free(buf);
1109 } else {
Tom Cherryd162f142019-10-24 17:35:26 -07001110 LogcatPanic(HELP_FALSE, "failed to set the prune list (alloc)");
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001111 }
Tom Cherryd162f142019-10-24 17:35:26 -07001112 return EXIT_SUCCESS;
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001113 }
1114
Mark Salyzyn1c950472014-04-01 17:19:47 -07001115 if (printStatistics || getPruneList) {
Mark Salyzyn34facab2014-02-06 14:48:50 -08001116 size_t len = 8192;
Mark Salyzyn5f606602017-02-10 13:09:07 -08001117 char* buf;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001118
Mark Salyzyn5f606602017-02-10 13:09:07 -08001119 for (int retry = 32; (retry >= 0) && ((buf = new char[len]));
Mark Salyzynde022a82017-03-01 08:30:06 -08001120 delete[] buf, buf = nullptr, --retry) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001121 if (getPruneList) {
Tom Cherry6f061e82019-10-29 07:05:24 -07001122 android_logger_get_prune_list(logger_list.get(), buf, len);
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001123 } else {
Tom Cherry6f061e82019-10-29 07:05:24 -07001124 android_logger_get_statistics(logger_list.get(), buf, len);
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001125 }
Mark Salyzyn5f606602017-02-10 13:09:07 -08001126 buf[len - 1] = '\0';
Traian Schiau59763032015-04-10 15:51:39 +03001127 if (atol(buf) < 3) {
Mark Salyzyn5f606602017-02-10 13:09:07 -08001128 delete[] buf;
Mark Salyzynde022a82017-03-01 08:30:06 -08001129 buf = nullptr;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001130 break;
1131 }
Traian Schiau59763032015-04-10 15:51:39 +03001132 size_t ret = atol(buf) + 1;
1133 if (ret <= len) {
1134 len = ret;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001135 break;
1136 }
Traian Schiau59763032015-04-10 15:51:39 +03001137 len = ret;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001138 }
1139
1140 if (!buf) {
Tom Cherryd162f142019-10-24 17:35:26 -07001141 LogcatPanic(HELP_FALSE, "failed to read data");
Mark Salyzyn34facab2014-02-06 14:48:50 -08001142 }
1143
1144 // remove trailing FF
Mark Salyzyn5f606602017-02-10 13:09:07 -08001145 char* cp = buf + len - 1;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001146 *cp = '\0';
1147 bool truncated = *--cp != '\f';
Mark Salyzynde022a82017-03-01 08:30:06 -08001148 if (!truncated) *cp = '\0';
Mark Salyzyn34facab2014-02-06 14:48:50 -08001149
1150 // squash out the byte count
1151 cp = buf;
1152 if (!truncated) {
Mark Salyzynde022a82017-03-01 08:30:06 -08001153 while (isdigit(*cp)) ++cp;
1154 if (*cp == '\n') ++cp;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001155 }
1156
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001157 len = strlen(cp);
Tom Cherryd162f142019-10-24 17:35:26 -07001158 TEMP_FAILURE_RETRY(write(output_fd_.get(), cp, len));
Mark Salyzyn5f606602017-02-10 13:09:07 -08001159 delete[] buf;
Tom Cherryd162f142019-10-24 17:35:26 -07001160 return EXIT_SUCCESS;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001161 }
1162
Tom Cherryd162f142019-10-24 17:35:26 -07001163 if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001164
Tom Cherryd162f142019-10-24 17:35:26 -07001165 SetupOutputAndSchedulingPolicy(!(mode & ANDROID_LOG_NONBLOCK));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001166
Tom Cherryd162f142019-10-24 17:35:26 -07001167 while (!max_count_ || print_count_ < max_count_) {
Mark Salyzyn95132e92013-11-22 10:55:48 -08001168 struct log_msg log_msg;
Tom Cherry6f061e82019-10-29 07:05:24 -07001169 int ret = android_logger_list_read(logger_list.get(), &log_msg);
Mark Salyzynde022a82017-03-01 08:30:06 -08001170 if (!ret) {
Tom Cherry41697322019-11-21 10:31:06 -08001171 LogcatPanic(HELP_FALSE, R"init(read: unexpected EOF!
1172
1173This means that either logd crashed, or more likely, this instance of logcat was unable to read log
1174messages as quickly as they were being produced.
1175
1176If you have enabled significant logging, look into using the -G option to increase log buffer sizes.
1177)init");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001178 }
1179
1180 if (ret < 0) {
Mark Salyzynde022a82017-03-01 08:30:06 -08001181 if (ret == -EAGAIN) break;
Mark Salyzyn95132e92013-11-22 10:55:48 -08001182
1183 if (ret == -EIO) {
Tom Cherryd162f142019-10-24 17:35:26 -07001184 LogcatPanic(HELP_FALSE, "read: unexpected EOF!\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001185 }
1186 if (ret == -EINVAL) {
Tom Cherryd162f142019-10-24 17:35:26 -07001187 LogcatPanic(HELP_FALSE, "read: unexpected length.\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001188 }
Tom Cherryd162f142019-10-24 17:35:26 -07001189 LogcatPanic(HELP_FALSE, "logcat read failure\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001190 }
1191
Tom Cherry6f061e82019-10-29 07:05:24 -07001192 if (log_msg.id() > LOG_ID_MAX) {
1193 LogcatPanic(HELP_FALSE, "read: unexpected log id (%d) over LOG_ID_MAX (%d)",
1194 log_msg.id(), LOG_ID_MAX);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001195 }
1196
Tom Cherry6f061e82019-10-29 07:05:24 -07001197 PrintDividers(log_msg.id(), printDividers);
1198
Tom Cherryd162f142019-10-24 17:35:26 -07001199 if (print_binary_) {
1200 TEMP_FAILURE_RETRY(write(output_fd_.get(), &log_msg, log_msg.len()));
Mark Salyzyn95132e92013-11-22 10:55:48 -08001201 } else {
Tom Cherry6f061e82019-10-29 07:05:24 -07001202 ProcessBuffer(&log_msg);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001203 }
1204 }
Tom Cherryd162f142019-10-24 17:35:26 -07001205 return EXIT_SUCCESS;
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001206}
1207
Tom Cherry98c6c332019-10-30 13:51:03 -07001208int main(int argc, char** argv) {
Tom Cherryd162f142019-10-24 17:35:26 -07001209 Logcat logcat;
1210 return logcat.Run(argc, argv);
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001211}