blob: 6b7e016a4c0ce7959b49026fba81efb33a11463d [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>
Tom Cherry72a4e082019-12-06 10:25:37 -080020#include <error.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080021#include <fcntl.h>
Elliott Hughes61b580e2018-06-15 15:16:20 -070022#include <getopt.h>
Aristidis Papaioannoueba73442014-10-16 22:19:55 -070023#include <math.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070024#include <sched.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070025#include <stdarg.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080026#include <stdio.h>
27#include <stdlib.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080028#include <string.h>
Traian Schiau59763032015-04-10 15:51:39 +030029#include <sys/cdefs.h>
Jaegeuk Kim5327d932019-07-04 18:09:38 -070030#include <sys/ioctl.h>
Riley Andrewsaede9892015-06-08 23:36:34 -070031#include <sys/resource.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080032#include <sys/stat.h>
Mark Salyzynf3555d92015-05-27 07:39:56 -070033#include <sys/types.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070034#include <time.h>
35#include <unistd.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080036
Mark Salyzynf3555d92015-05-27 07:39:56 -070037#include <memory>
Elliott Hughesaddd8522019-08-08 08:53:59 -070038#include <regex>
Tom Cherry9291f0f2020-04-13 10:07:53 -070039#include <set>
Mark Salyzynf3555d92015-05-27 07:39:56 -070040#include <string>
Wei Wangc27d4812018-09-05 11:05:57 -070041#include <utility>
Mark Salyzyn1d6928b2017-02-10 13:09:07 -080042#include <vector>
Mark Salyzynf3555d92015-05-27 07:39:56 -070043
Elliott Hughes4f713192015-12-04 22:00:26 -080044#include <android-base/file.h>
Tom Cherryd162f142019-10-24 17:35:26 -070045#include <android-base/macros.h>
Tom Cherry6f061e82019-10-29 07:05:24 -070046#include <android-base/parseint.h>
bohu94aab862017-02-21 14:31:19 -080047#include <android-base/properties.h>
Mark Salyzyn5b1a5382016-08-03 14:20:41 -070048#include <android-base/stringprintf.h>
Elliott Hughes4f713192015-12-04 22:00:26 -080049#include <android-base/strings.h>
Tom Cherryd162f142019-10-24 17:35:26 -070050#include <android-base/unique_fd.h>
Tom Cherry6f061e82019-10-29 07:05:24 -070051#include <android/log.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070052#include <log/event_tag_map.h>
Tom Cherry6f061e82019-10-29 07:05:24 -070053#include <log/log_id.h>
Tom Cherryc5c6d7d2020-04-17 09:38:55 -070054#include <log/log_read.h>
Colin Cross9227bd32013-07-23 16:59:20 -070055#include <log/logprint.h>
Mark Salyzynaeaaf812016-09-30 13:30:33 -070056#include <private/android_logger.h>
Suren Baghdasaryan02843332018-12-21 12:30:16 -080057#include <processgroup/sched_policy.h>
Elliott Hughesb9e53b42016-02-17 11:58:01 -080058#include <system/thread_defs.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080059
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080060#define DEFAULT_MAX_ROTATED_LOGS 4
61
Tom Cherry6f061e82019-10-29 07:05:24 -070062using android::base::Join;
63using android::base::ParseByteCount;
64using android::base::ParseUint;
65using android::base::Split;
Tom Cherryd162f142019-10-24 17:35:26 -070066using android::base::StringPrintf;
Tom Cherry3e970d42020-08-05 14:01:11 -070067using android::base::WriteFully;
Tom Cherryd162f142019-10-24 17:35:26 -070068
Tom Cherryd162f142019-10-24 17:35:26 -070069class Logcat {
70 public:
Tom Cherryd162f142019-10-24 17:35:26 -070071 int Run(int argc, char** argv);
Mark Salyzync0cf90d2017-02-10 13:09:07 -080072
Tom Cherryd162f142019-10-24 17:35:26 -070073 private:
74 void RotateLogs();
Tom Cherry6f061e82019-10-29 07:05:24 -070075 void ProcessBuffer(struct log_msg* buf);
76 void PrintDividers(log_id_t log_id, bool print_dividers);
Tom Cherryd162f142019-10-24 17:35:26 -070077 void SetupOutputAndSchedulingPolicy(bool blocking);
78 int SetLogFormat(const char* format_string);
79
Tom Cherry6f061e82019-10-29 07:05:24 -070080 // Used for all options
Tom Cherryd162f142019-10-24 17:35:26 -070081 android::base::unique_fd output_fd_{dup(STDOUT_FILENO)};
82 std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
83 android_log_format_new(), &android_log_format_free};
Tom Cherry6f061e82019-10-29 07:05:24 -070084
85 // For logging to a file and log rotation
Tom Cherryd162f142019-10-24 17:35:26 -070086 const char* output_file_name_ = nullptr;
Tom Cherry6f061e82019-10-29 07:05:24 -070087 size_t log_rotate_size_kb_ = 0; // 0 means "no log rotation"
88 size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
Tom Cherryd162f142019-10-24 17:35:26 -070089 size_t out_byte_count_ = 0;
Tom Cherry6f061e82019-10-29 07:05:24 -070090
91 // For binary log buffers
Tom Cherryd162f142019-10-24 17:35:26 -070092 int print_binary_ = 0;
Tom Cherryd162f142019-10-24 17:35:26 -070093 std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
94 nullptr, &android_closeEventTagMap};
Tom Cherryd162f142019-10-24 17:35:26 -070095 bool has_opened_event_tag_map_ = false;
Tom Cherry6f061e82019-10-29 07:05:24 -070096
97 // For the related --regex, --max-count, --print
98 std::unique_ptr<std::regex> regex_;
99 size_t max_count_ = 0; // 0 means "infinite"
100 size_t print_count_ = 0;
101 bool print_it_anyways_ = false;
102
103 // For PrintDividers()
104 log_id_t last_printed_id_ = LOG_ID_MAX;
105 bool printed_start_[LOG_ID_MAX] = {};
106
107 bool debug_ = false;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800108};
109
Jaegeuk Kim5327d932019-07-04 18:09:38 -0700110#ifndef F2FS_IOC_SET_PIN_FILE
111#define F2FS_IOCTL_MAGIC 0xf5
112#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
113#endif
114
115static int openLogFile(const char* pathname, size_t sizeKB) {
Mike Maa7fb0952020-01-17 18:01:03 -0800116 int fd = open(pathname, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP);
Jaegeuk Kim5327d932019-07-04 18:09:38 -0700117 if (fd < 0) {
118 return fd;
119 }
120
121 // no need to check errors
122 __u32 set = 1;
123 ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
124 fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, (sizeKB << 10));
125 return fd;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800126}
127
Jaegeuk Kim2e5b7c42020-04-23 08:28:35 -0700128static void closeLogFile(const char* pathname) {
129 int fd = open(pathname, O_WRONLY | O_CLOEXEC);
130 if (fd == -1) {
131 return;
132 }
133
134 // no need to check errors
135 __u32 set = 0;
136 ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
137 close(fd);
138}
139
Tom Cherryd162f142019-10-24 17:35:26 -0700140void Logcat::RotateLogs() {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800141 // Can't rotate logs if we're not outputting to a file
Tom Cherryd162f142019-10-24 17:35:26 -0700142 if (!output_file_name_) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800143
Tom Cherryd162f142019-10-24 17:35:26 -0700144 output_fd_.reset();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800145
Mark Salyzyn5f606602017-02-10 13:09:07 -0800146 // Compute the maximum number of digits needed to count up to
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800147 // maxRotatedLogs in decimal. eg:
148 // maxRotatedLogs == 30
Mark Salyzyn5f606602017-02-10 13:09:07 -0800149 // -> log10(30) == 1.477
150 // -> maxRotationCountDigits == 2
Tom Cherryd162f142019-10-24 17:35:26 -0700151 int max_rotation_count_digits =
152 max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
Aristidis Papaioannoueba73442014-10-16 22:19:55 -0700153
Tom Cherryd162f142019-10-24 17:35:26 -0700154 for (int i = max_rotated_logs_; i > 0; i--) {
155 std::string file1 =
156 StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800157
Mark Salyzyn5b1a5382016-08-03 14:20:41 -0700158 std::string file0;
Mark Salyzynde022a82017-03-01 08:30:06 -0800159 if (!(i - 1)) {
Tom Cherryd162f142019-10-24 17:35:26 -0700160 file0 = output_file_name_;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800161 } else {
Tom Cherryd162f142019-10-24 17:35:26 -0700162 file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800163 }
164
Mark Salyzynde022a82017-03-01 08:30:06 -0800165 if (!file0.length() || !file1.length()) {
Traian Schiau59763032015-04-10 15:51:39 +0300166 perror("while rotating log files");
167 break;
168 }
169
Jaegeuk Kim2e5b7c42020-04-23 08:28:35 -0700170 closeLogFile(file0.c_str());
171
Tom Cherryd162f142019-10-24 17:35:26 -0700172 int err = rename(file0.c_str(), file1.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800173
174 if (err < 0 && errno != ENOENT) {
175 perror("while rotating log files");
176 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800177 }
178
Tom Cherryd162f142019-10-24 17:35:26 -0700179 output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800180
Tom Cherryd162f142019-10-24 17:35:26 -0700181 if (!output_fd_.ok()) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800182 error(EXIT_FAILURE, errno, "Couldn't open output file");
Mark Salyzyne3d0c962017-02-17 13:15:51 -0800183 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800184
Tom Cherryd162f142019-10-24 17:35:26 -0700185 out_byte_count_ = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800186}
187
Tom Cherry6f061e82019-10-29 07:05:24 -0700188void Logcat::ProcessBuffer(struct log_msg* buf) {
Mathias Agopian50844522010-03-17 16:10:26 -0700189 int bytesWritten = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800190 int err;
191 AndroidLogEntry entry;
192 char binaryMsgBuf[1024];
193
Tom Cherry6f061e82019-10-29 07:05:24 -0700194 bool is_binary =
195 buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
196
197 if (is_binary) {
Tom Cherryd162f142019-10-24 17:35:26 -0700198 if (!event_tag_map_ && !has_opened_event_tag_map_) {
199 event_tag_map_.reset(android_openEventTagMap(nullptr));
200 has_opened_event_tag_map_ = true;
Mark Salyzyn9421b0c2015-02-26 14:33:35 -0800201 }
Tom Cherryd162f142019-10-24 17:35:26 -0700202 err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
Tom Cherry441054a2019-10-15 16:53:11 -0700203 binaryMsgBuf, sizeof(binaryMsgBuf));
Mark Salyzyn5f606602017-02-10 13:09:07 -0800204 // printf(">>> pri=%d len=%d msg='%s'\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800205 // entry.priority, entry.messageLen, entry.message);
206 } else {
Tom Cherry441054a2019-10-15 16:53:11 -0700207 err = android_log_processLogBuffer(&buf->entry, &entry);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800208 }
Tom Cherryd162f142019-10-24 17:35:26 -0700209 if (err < 0 && !debug_) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800210
Tom Cherryd162f142019-10-24 17:35:26 -0700211 if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
212 entry.priority)) {
213 bool match = !regex_ ||
214 std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800215
Tom Cherryd162f142019-10-24 17:35:26 -0700216 print_count_ += match;
217 if (match || print_it_anyways_) {
218 bytesWritten = android_log_printLogLine(logformat_.get(), output_fd_.get(), &entry);
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700219
Mark Salyzync9202772016-03-30 09:38:31 -0700220 if (bytesWritten < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800221 error(EXIT_FAILURE, 0, "Output error.");
Mark Salyzync9202772016-03-30 09:38:31 -0700222 }
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800223 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800224 }
225
Tom Cherryd162f142019-10-24 17:35:26 -0700226 out_byte_count_ += bytesWritten;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800227
Tom Cherryd162f142019-10-24 17:35:26 -0700228 if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
229 RotateLogs();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800230 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800231}
232
Tom Cherry6f061e82019-10-29 07:05:24 -0700233void Logcat::PrintDividers(log_id_t log_id, bool print_dividers) {
234 if (log_id == last_printed_id_ || print_binary_) {
235 return;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800236 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700237 if (!printed_start_[log_id] || print_dividers) {
238 if (dprintf(output_fd_.get(), "--------- %s %s\n",
239 printed_start_[log_id] ? "switch to" : "beginning of",
240 android_log_id_to_name(log_id)) < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800241 error(EXIT_FAILURE, errno, "Output error");
Tom Cherry6f061e82019-10-29 07:05:24 -0700242 }
243 }
244 last_printed_id_ = log_id;
245 printed_start_[log_id] = true;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800246}
247
Tom Cherryd162f142019-10-24 17:35:26 -0700248void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
249 if (!output_file_name_) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800250
Mark Salyzynad5e4112016-08-04 07:53:52 -0700251 if (blocking) {
252 // Lower priority and set to batch scheduling if we are saving
253 // the logs into files and taking continuous content.
Tom Cherryd162f142019-10-24 17:35:26 -0700254 if (set_sched_policy(0, SP_BACKGROUND) < 0) {
255 fprintf(stderr, "failed to set background scheduling policy\n");
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700256 }
257
Tom Cherryd162f142019-10-24 17:35:26 -0700258 struct sched_param param = {};
Mark Salyzyn5f606602017-02-10 13:09:07 -0800259 if (sched_setscheduler((pid_t)0, SCHED_BATCH, &param) < 0) {
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700260 fprintf(stderr, "failed to set to batch scheduler\n");
261 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800262
Tom Cherryd162f142019-10-24 17:35:26 -0700263 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
264 fprintf(stderr, "failed set to priority\n");
Riley Andrewsaede9892015-06-08 23:36:34 -0700265 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800266 }
Mark Salyzynad5e4112016-08-04 07:53:52 -0700267
Tom Cherryd162f142019-10-24 17:35:26 -0700268 output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
Mark Salyzynad5e4112016-08-04 07:53:52 -0700269
Tom Cherryd162f142019-10-24 17:35:26 -0700270 if (!output_fd_.ok()) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800271 error(EXIT_FAILURE, errno, "Couldn't open output file");
Mark Salyzynad5e4112016-08-04 07:53:52 -0700272 }
273
274 struct stat statbuf;
Tom Cherryd162f142019-10-24 17:35:26 -0700275 if (fstat(output_fd_.get(), &statbuf) == -1) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800276 error(EXIT_FAILURE, errno, "Couldn't get output file stat");
Mark Salyzynad5e4112016-08-04 07:53:52 -0700277 }
278
Mark Salyzyn5f606602017-02-10 13:09:07 -0800279 if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800280 error(EXIT_FAILURE, 0, "Invalid output file stat.");
Mark Salyzynad5e4112016-08-04 07:53:52 -0700281 }
282
Tom Cherryd162f142019-10-24 17:35:26 -0700283 out_byte_count_ = statbuf.st_size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800284}
285
Mark Salyzyn5f606602017-02-10 13:09:07 -0800286// clang-format off
Tom Cherryd162f142019-10-24 17:35:26 -0700287static void show_help() {
288 const char* cmd = getprogname();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800289
Tom Cherryd162f142019-10-24 17:35:26 -0700290 fprintf(stderr, "Usage: %s [options] [filterspecs]\n", cmd);
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800291
Tom Cherry41697322019-11-21 10:31:06 -0800292 fprintf(stderr, R"init(
293General options:
294 -b, --buffer=<buffer> Request alternate ring buffer(s):
295 main system radio events crash default all
296 Additionally, 'kernel' for userdebug and eng builds, and
297 'security' for Device Owner installations.
298 Multiple -b parameters or comma separated list of buffers are
299 allowed. Buffers are interleaved.
300 Default -b main,system,crash,kernel.
301 -L, --last Dump logs from prior to last reboot from pstore.
302 -c, --clear Clear (flush) the entire log and exit.
303 if -f is specified, clear the specified file and its related rotated
304 log files instead.
305 if -L is specified, clear pstore log instead.
306 -d Dump the log and then exit (don't block).
307 --pid=<pid> Only print logs from the given pid.
308 --wrap Sleep for 2 hours or when buffer about to wrap whichever
309 comes first. Improves efficiency of polling by providing
310 an about-to-wrap wakeup.
311
312Formatting:
313 -v, --format=<format> Sets log print format verb and adverbs, where <format> is one of:
314 brief help long process raw tag thread threadtime time
315 Modifying adverbs can be added:
316 color descriptive epoch monotonic printable uid usec UTC year zone
317 Multiple -v parameters or comma separated list of format and format
318 modifiers are allowed.
319 -D, --dividers Print dividers between each log buffer.
320 -B, --binary Output the log in binary.
321
322Outfile files:
323 -f, --file=<file> Log to file instead of stdout.
324 -r, --rotate-kbytes=<n> Rotate log every <n> kbytes. Requires -f option.
325 -n, --rotate-count=<count> Sets max number of rotated logs to <count>, default 4.
326 --id=<id> If the signature <id> for logging to file changes, then clear the
327 associated files and continue.
328
329Logd control:
330 These options send a control message to the logd daemon on device, print its return message if
331 applicable, then exit. They are incompatible with -L, as these attributes do not apply to pstore.
332 -g, --buffer-size Get the size of the ring buffers within logd.
333 -G, --buffer-size=<size> Set size of a ring buffer in logd. May suffix with K or M.
334 This can individually control each buffer's size with -b.
335 -S, --statistics Output statistics.
336 --pid can be used to provide pid specific stats.
Tom Cherry0efb4102020-06-16 10:14:09 -0700337 -p, --prune Print prune rules. Each rule is specified as UID, UID/PID or /PID. A
338 '~' prefix indicates that elements matching the rule should be pruned
339 with higher priority otherwise they're pruned with lower priority. All
340 other pruning activity is oldest first. Special case ~! represents an
341 automatic pruning for the noisiest UID as determined by the current
342 statistics. Special case ~1000/! represents pruning of the worst PID
343 within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
344 -P, --prune='<list> ...' Set prune rules, using same format as listed above. Must be quoted.
Tom Cherry41697322019-11-21 10:31:06 -0800345
346Filtering:
347 -s Set default filter to silent. Equivalent to filterspec '*:S'
348 -e, --regex=<expr> Only print lines where the log message matches <expr> where <expr> is
349 an ECMAScript regular expression.
350 -m, --max-count=<count> Quit after printing <count> lines. This is meant to be paired with
351 --regex, but will work on its own.
352 --print This option is only applicable when --regex is set and only useful if
353 --max-count is also provided.
354 With --print, logcat will print all messages even if they do not
355 match the regex. Logcat will quit after printing the max-count number
356 of lines that match the regex.
357 -t <count> Print only the most recent <count> lines (implies -d).
358 -t '<time>' Print the lines since specified time (implies -d).
359 -T <count> Print only the most recent <count> lines (does not imply -d).
360 -T '<time>' Print the lines since specified time (not imply -d).
361 count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
362 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format.
Tom Cherry9291f0f2020-04-13 10:07:53 -0700363 --uid=<uids> Only display log messages from UIDs present in the comma separate list
364 <uids>. No name look-up is performed, so UIDs must be provided as
365 numeric values. This option is only useful for the 'root', 'log', and
366 'system' users since only those users can view logs from other users.
Tom Cherry41697322019-11-21 10:31:06 -0800367)init");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800368
Tom Cherryd162f142019-10-24 17:35:26 -0700369 fprintf(stderr, "\nfilterspecs are a series of \n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800370 " <tag>[:priority]\n\n"
371 "where <tag> is a log component tag (or * for all) and priority is:\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700372 " V Verbose (default for <tag>)\n"
373 " D Debug (default for '*')\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800374 " I Info\n"
375 " W Warn\n"
376 " E Error\n"
377 " F Fatal\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700378 " S Silent (suppress all output)\n"
379 "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
380 "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
381 "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
382 "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
383 "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
Mark Salyzyn649fc602014-09-16 09:15:15 -0700384 "or defaults to \"threadtime\"\n\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800385}
386
Tom Cherryd162f142019-10-24 17:35:26 -0700387static void show_format_help() {
388 fprintf(stderr,
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700389 "-v <format>, --format=<format> options:\n"
390 " Sets log print format verb and adverbs, where <format> is:\n"
391 " brief long process raw tag thread threadtime time\n"
392 " and individually flagged modifying adverbs can be added:\n"
393 " color descriptive epoch monotonic printable uid usec UTC year zone\n"
394 "\nSingle format verbs:\n"
395 " brief — Display priority/tag and PID of the process issuing the message.\n"
396 " long — Display all metadata fields, separate messages with blank lines.\n"
397 " process — Display PID only.\n"
398 " raw — Display the raw log message, with no other metadata fields.\n"
399 " tag — Display the priority/tag only.\n"
Mark Salyzync74f8d92017-05-15 13:40:33 -0700400 " thread — Display priority, PID and TID of process issuing the message.\n"
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700401 " threadtime — Display the date, invocation time, priority, tag, and the PID\n"
402 " and TID of the thread issuing the message. (the default format).\n"
403 " time — Display the date, invocation time, priority/tag, and PID of the\n"
404 " process issuing the message.\n"
405 "\nAdverb modifiers can be used in combination:\n"
Peter Kalauskas8b477b62020-06-18 16:55:24 -0700406 " color — Display in highlighted color to match priority. i.e. \x1B[39mVERBOSE\n"
407 " \x1B[34mDEBUG \x1B[32mINFO \x1B[33mWARNING \x1B[31mERROR FATAL\x1B[0m\n"
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700408 " descriptive — events logs only, descriptions from event-log-tags database.\n"
409 " epoch — Display time as seconds since Jan 1 1970.\n"
410 " monotonic — Display time as cpu seconds since last boot.\n"
411 " printable — Ensure that any binary logging content is escaped.\n"
412 " uid — If permitted, display the UID or Android ID of logged process.\n"
413 " usec — Display time down the microsecond precision.\n"
414 " UTC — Display time as UTC.\n"
415 " year — Add the year to the displayed time.\n"
416 " zone — Add the local timezone to the displayed time.\n"
417 " \"<zone>\" — Print using this public named timezone (experimental).\n\n"
418 );
419}
Mark Salyzyn5f606602017-02-10 13:09:07 -0800420// clang-format on
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700421
Tom Cherryd162f142019-10-24 17:35:26 -0700422int Logcat::SetLogFormat(const char* format_string) {
423 AndroidLogPrintFormat format = android_log_formatFromString(format_string);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800424
Mark Salyzynde022a82017-03-01 08:30:06 -0800425 // invalid string?
426 if (format == FORMAT_OFF) return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800427
Tom Cherryd162f142019-10-24 17:35:26 -0700428 return android_log_setPrintFormat(logformat_.get(), format);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800429}
430
Wei Wangc27d4812018-09-05 11:05:57 -0700431static std::pair<unsigned long, const char*> format_of_size(unsigned long value) {
432 static const char multipliers[][3] = {{""}, {"Ki"}, {"Mi"}, {"Gi"}};
433 size_t i;
Mark Salyzyn671e3432014-05-06 07:34:59 -0700434 for (i = 0;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800435 (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
436 value /= 1024, ++i)
437 ;
Wei Wangc27d4812018-09-05 11:05:57 -0700438 return std::make_pair(value, multipliers[i]);
Mark Salyzyn671e3432014-05-06 07:34:59 -0700439}
440
Mark Salyzyn5f606602017-02-10 13:09:07 -0800441static char* parseTime(log_time& t, const char* cp) {
442 char* ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
Mark Salyzynde022a82017-03-01 08:30:06 -0800443 if (ep) return ep;
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700444 ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
Mark Salyzynde022a82017-03-01 08:30:06 -0800445 if (ep) return ep;
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700446 return t.strptime(cp, "%s.%q");
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700447}
Mark Salyzynf3555d92015-05-27 07:39:56 -0700448
Mark Salyzyn31961062016-08-04 07:43:46 -0700449// Find last logged line in <outputFileName>, or <outputFileName>.1
Mark Salyzyne9ade172017-03-02 15:09:41 -0800450static log_time lastLogTime(const char* outputFileName) {
Mark Salyzynf3555d92015-05-27 07:39:56 -0700451 log_time retval(log_time::EPOCH);
Mark Salyzynde022a82017-03-01 08:30:06 -0800452 if (!outputFileName) return retval;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700453
Mark Salyzynf3555d92015-05-27 07:39:56 -0700454 std::string directory;
Mark Salyzyne9ade172017-03-02 15:09:41 -0800455 const char* file = strrchr(outputFileName, '/');
Mark Salyzynf3555d92015-05-27 07:39:56 -0700456 if (!file) {
457 directory = ".";
458 file = outputFileName;
459 } else {
Mark Salyzyne9ade172017-03-02 15:09:41 -0800460 directory = std::string(outputFileName, file - outputFileName);
Mark Salyzynf3555d92015-05-27 07:39:56 -0700461 ++file;
462 }
Mark Salyzync18c2132016-04-01 07:52:20 -0700463
Mark Salyzyn5f606602017-02-10 13:09:07 -0800464 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()),
465 closedir);
Mark Salyzynde022a82017-03-01 08:30:06 -0800466 if (!dir.get()) return retval;
Mark Salyzync18c2132016-04-01 07:52:20 -0700467
Tom Cherryf2c27462020-04-08 14:36:05 -0700468 log_time now(CLOCK_REALTIME);
Mark Salyzync18c2132016-04-01 07:52:20 -0700469
Mark Salyzynf3555d92015-05-27 07:39:56 -0700470 size_t len = strlen(file);
471 log_time modulo(0, NS_PER_SEC);
Mark Salyzyn5f606602017-02-10 13:09:07 -0800472 struct dirent* dp;
Mark Salyzync18c2132016-04-01 07:52:20 -0700473
Mark Salyzynde022a82017-03-01 08:30:06 -0800474 while (!!(dp = readdir(dir.get()))) {
475 if ((dp->d_type != DT_REG) || !!strncmp(dp->d_name, file, len) ||
Mark Salyzyn5f606602017-02-10 13:09:07 -0800476 (dp->d_name[len] && ((dp->d_name[len] != '.') ||
Mark Salyzynde022a82017-03-01 08:30:06 -0800477 (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) {
Mark Salyzynf3555d92015-05-27 07:39:56 -0700478 continue;
479 }
480
481 std::string file_name = directory;
482 file_name += "/";
483 file_name += dp->d_name;
484 std::string file;
Mark Salyzynde022a82017-03-01 08:30:06 -0800485 if (!android::base::ReadFileToString(file_name, &file)) continue;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700486
487 bool found = false;
488 for (const auto& line : android::base::Split(file, "\n")) {
489 log_time t(log_time::EPOCH);
Mark Salyzyn5f606602017-02-10 13:09:07 -0800490 char* ep = parseTime(t, line.c_str());
Mark Salyzynde022a82017-03-01 08:30:06 -0800491 if (!ep || (*ep != ' ')) continue;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700492 // determine the time precision of the logs (eg: msec or usec)
493 for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
494 if (t.tv_nsec % (mod * 10)) {
495 modulo.tv_nsec = mod;
496 break;
497 }
498 }
499 // We filter any times later than current as we may not have the
500 // year stored with each log entry. Also, since it is possible for
501 // entries to be recorded out of order (very rare) we select the
502 // maximum we find just in case.
503 if ((t < now) && (t > retval)) {
504 retval = t;
505 found = true;
506 }
507 }
508 // We count on the basename file to be the definitive end, so stop here.
Mark Salyzynde022a82017-03-01 08:30:06 -0800509 if (!dp->d_name[len] && found) break;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700510 }
Mark Salyzynde022a82017-03-01 08:30:06 -0800511 if (retval == log_time::EPOCH) return retval;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700512 // tail_time prints matching or higher, round up by the modulo to prevent
513 // a replay of the last entry we have just checked.
514 retval += modulo;
515 return retval;
516}
517
Tom Cherry6f061e82019-10-29 07:05:24 -0700518void ReportErrorName(const std::string& name, bool allow_security,
519 std::vector<std::string>* errors) {
520 if (allow_security || name != "security") {
521 errors->emplace_back(name);
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800522 }
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800523}
Traian Schiau59763032015-04-10 15:51:39 +0300524
Tom Cherryd162f142019-10-24 17:35:26 -0700525int Logcat::Run(int argc, char** argv) {
Mark Salyzynb45a1752017-02-28 09:20:31 -0800526 bool hasSetLogFormat = false;
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800527 bool clearLog = false;
Tom Cherry6f061e82019-10-29 07:05:24 -0700528 bool security_buffer_selected =
529 false; // Do not report errors on the security buffer unless it is explicitly named.
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800530 bool getLogSize = false;
531 bool getPruneList = false;
532 bool printStatistics = false;
533 bool printDividers = false;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800534 unsigned long setLogSize = 0;
Mark Salyzyne9ade172017-03-02 15:09:41 -0800535 const char* setPruneList = nullptr;
536 const char* setId = nullptr;
Tom Cherry907b2d02020-03-23 13:40:10 -0700537 int mode = 0;
Mark Salyzynf3290292017-02-10 13:09:07 -0800538 std::string forceFilters;
Traian Schiau59763032015-04-10 15:51:39 +0300539 size_t tail_lines = 0;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800540 log_time tail_time(log_time::EPOCH);
Kristian Monsen562e5132015-06-05 14:10:12 -0700541 size_t pid = 0;
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700542 bool got_t = false;
Tom Cherry6f061e82019-10-29 07:05:24 -0700543 unsigned id_mask = 0;
Tom Cherry9291f0f2020-04-13 10:07:53 -0700544 std::set<uid_t> uids;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800545
Mark Salyzynde022a82017-03-01 08:30:06 -0800546 if (argc == 2 && !strcmp(argv[1], "--help")) {
Tom Cherryd162f142019-10-24 17:35:26 -0700547 show_help();
548 return EXIT_SUCCESS;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800549 }
550
Mark Salyzynb45a1752017-02-28 09:20:31 -0800551 // meant to catch comma-delimited values, but cast a wider
552 // net for stability dealing with possible mistaken inputs.
553 static const char delimiters[] = ",:; \t\n\r\f";
554
Elliott Hughes61b580e2018-06-15 15:16:20 -0700555 optind = 0;
556 while (true) {
Kristian Monsen562e5132015-06-05 14:10:12 -0700557 int option_index = 0;
Mark Salyzync9202772016-03-30 09:38:31 -0700558 // list of long-argument only strings for later comparison
Kristian Monsen562e5132015-06-05 14:10:12 -0700559 static const char pid_str[] = "pid";
Mark Salyzyn538bc122016-11-16 15:28:31 -0800560 static const char debug_str[] = "debug";
Mark Salyzyn02687e72016-08-03 14:20:41 -0700561 static const char id_str[] = "id";
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800562 static const char wrap_str[] = "wrap";
Mark Salyzync9202772016-03-30 09:38:31 -0700563 static const char print_str[] = "print";
Tom Cherry9291f0f2020-04-13 10:07:53 -0700564 static const char uid_str[] = "uid";
Mark Salyzyn5f606602017-02-10 13:09:07 -0800565 // clang-format off
Kristian Monsen562e5132015-06-05 14:10:12 -0700566 static const struct option long_options[] = {
Mark Salyzynde022a82017-03-01 08:30:06 -0800567 { "binary", no_argument, nullptr, 'B' },
568 { "buffer", required_argument, nullptr, 'b' },
569 { "buffer-size", optional_argument, nullptr, 'g' },
570 { "clear", no_argument, nullptr, 'c' },
571 { debug_str, no_argument, nullptr, 0 },
572 { "dividers", no_argument, nullptr, 'D' },
573 { "file", required_argument, nullptr, 'f' },
574 { "format", required_argument, nullptr, 'v' },
Mark Salyzync18c2132016-04-01 07:52:20 -0700575 // hidden and undocumented reserved alias for --regex
Mark Salyzynde022a82017-03-01 08:30:06 -0800576 { "grep", required_argument, nullptr, 'e' },
Mark Salyzynd85f6462016-03-30 09:15:09 -0700577 // hidden and undocumented reserved alias for --max-count
Mark Salyzynde022a82017-03-01 08:30:06 -0800578 { "head", required_argument, nullptr, 'm' },
Mark Salyzyne74e51d2017-04-03 09:30:20 -0700579 { "help", no_argument, nullptr, 'h' },
Mark Salyzynde022a82017-03-01 08:30:06 -0800580 { id_str, required_argument, nullptr, 0 },
581 { "last", no_argument, nullptr, 'L' },
582 { "max-count", required_argument, nullptr, 'm' },
583 { pid_str, required_argument, nullptr, 0 },
584 { print_str, no_argument, nullptr, 0 },
585 { "prune", optional_argument, nullptr, 'p' },
586 { "regex", required_argument, nullptr, 'e' },
587 { "rotate-count", required_argument, nullptr, 'n' },
588 { "rotate-kbytes", required_argument, nullptr, 'r' },
589 { "statistics", no_argument, nullptr, 'S' },
Mark Salyzynd85f6462016-03-30 09:15:09 -0700590 // hidden and undocumented reserved alias for -t
Mark Salyzynde022a82017-03-01 08:30:06 -0800591 { "tail", required_argument, nullptr, 't' },
Tom Cherry9291f0f2020-04-13 10:07:53 -0700592 { uid_str, required_argument, nullptr, 0 },
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800593 // support, but ignore and do not document, the optional argument
Mark Salyzynde022a82017-03-01 08:30:06 -0800594 { wrap_str, optional_argument, nullptr, 0 },
595 { nullptr, 0, nullptr, 0 }
Kristian Monsen562e5132015-06-05 14:10:12 -0700596 };
Mark Salyzyn5f606602017-02-10 13:09:07 -0800597 // clang-format on
Kristian Monsen562e5132015-06-05 14:10:12 -0700598
Elliott Hughes61b580e2018-06-15 15:16:20 -0700599 int c = getopt_long(argc, argv, ":cdDhLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", long_options,
600 &option_index);
601 if (c == -1) break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800602
Elliott Hughes61b580e2018-06-15 15:16:20 -0700603 switch (c) {
Kristian Monsen562e5132015-06-05 14:10:12 -0700604 case 0:
Mark Salyzyn02687e72016-08-03 14:20:41 -0700605 // only long options
Kristian Monsen562e5132015-06-05 14:10:12 -0700606 if (long_options[option_index].name == pid_str) {
Steven Morelandb0e867a2019-08-02 10:13:57 -0700607 if (pid != 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800608 error(EXIT_FAILURE, 0, "Only one --pid argument can be provided.");
Steven Morelandb0e867a2019-08-02 10:13:57 -0700609 }
610
Tom Cherry6f061e82019-10-29 07:05:24 -0700611 if (!ParseUint(optarg, &pid) || pid < 1) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800612 error(EXIT_FAILURE, 0, "%s %s out of range.",
613 long_options[option_index].name, optarg);
Kristian Monsen562e5132015-06-05 14:10:12 -0700614 }
615 break;
616 }
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800617 if (long_options[option_index].name == wrap_str) {
Tom Cherry907b2d02020-03-23 13:40:10 -0700618 mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK;
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800619 // ToDo: implement API that supports setting a wrap timeout
Tom Cherry2d451662020-07-27 11:20:29 -0700620 size_t timeout = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
621 if (optarg && (!ParseUint(optarg, &timeout) || timeout < 1)) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800622 error(EXIT_FAILURE, 0, "%s %s out of range.",
623 long_options[option_index].name, optarg);
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800624 }
Tom Cherry2d451662020-07-27 11:20:29 -0700625 if (timeout != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
Tom Cherryd162f142019-10-24 17:35:26 -0700626 fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
627 long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
Tom Cherry2d451662020-07-27 11:20:29 -0700628 timeout);
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800629 }
630 break;
631 }
Mark Salyzync9202772016-03-30 09:38:31 -0700632 if (long_options[option_index].name == print_str) {
Tom Cherryd162f142019-10-24 17:35:26 -0700633 print_it_anyways_ = true;
Mark Salyzync9202772016-03-30 09:38:31 -0700634 break;
635 }
Mark Salyzyn538bc122016-11-16 15:28:31 -0800636 if (long_options[option_index].name == debug_str) {
Tom Cherryd162f142019-10-24 17:35:26 -0700637 debug_ = true;
Mark Salyzyn538bc122016-11-16 15:28:31 -0800638 break;
639 }
Mark Salyzyn02687e72016-08-03 14:20:41 -0700640 if (long_options[option_index].name == id_str) {
Elliott Hughes61b580e2018-06-15 15:16:20 -0700641 setId = (optarg && optarg[0]) ? optarg : nullptr;
Mark Salyzyn02687e72016-08-03 14:20:41 -0700642 }
Tom Cherry9291f0f2020-04-13 10:07:53 -0700643 if (long_options[option_index].name == uid_str) {
644 auto uid_strings = Split(optarg, delimiters);
645 for (const auto& uid_string : uid_strings) {
646 uid_t uid;
647 if (!ParseUint(uid_string, &uid)) {
648 error(EXIT_FAILURE, 0, "Unable to parse UID '%s'", uid_string.c_str());
649 }
650 uids.emplace(uid);
651 }
652 break;
653 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800654 break;
Kristian Monsen562e5132015-06-05 14:10:12 -0700655
Mark Salyzyn95132e92013-11-22 10:55:48 -0800656 case 's':
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800657 // default to all silent
Tom Cherryd162f142019-10-24 17:35:26 -0700658 android_log_addFilterRule(logformat_.get(), "*:s");
Mark Salyzyn5f606602017-02-10 13:09:07 -0800659 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800660
661 case 'c':
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800662 clearLog = true;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800663 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800664
Mark Salyzyn7c975ac2014-12-15 10:01:31 -0800665 case 'L':
Tom Cherry907b2d02020-03-23 13:40:10 -0700666 mode |= ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800667 break;
Mark Salyzyn7c975ac2014-12-15 10:01:31 -0800668
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800669 case 'd':
Tom Cherry907b2d02020-03-23 13:40:10 -0700670 mode |= 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;
Tom Cherry907b2d02020-03-23 13:40:10 -0700675 mode |= 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 Cherry72a4e082019-12-06 10:25:37 -0800681 error(EXIT_FAILURE, 0, "-%c '%s' not in time format.", 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 Cherry72a4e082019-12-06 10:25:37 -0800686 fprintf(stderr, "WARNING: -%c '%s' '%c%s' time truncated\n", c, optarg, ch,
687 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 Cherry72a4e082019-12-06 10:25:37 -0800708 error(EXIT_FAILURE, 0, "-%c '%s' isn't an integer greater than zero.", 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 Cherry72a4e082019-12-06 10:25:37 -0800722 error(EXIT_FAILURE, 0, "-G must be specified as <num><multiplier>.");
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) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800746 error(EXIT_FAILURE, 0, "Unknown buffer '%s' listed for -b.",
747 buffer.c_str());
Mark Salyzyn34facab2014-02-06 14:48:50 -0800748 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700749 if (log_id == LOG_ID_SECURITY) {
750 security_buffer_selected = true;
Mark Salyzyn083b0372015-12-04 10:59:45 -0800751 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700752 id_mask |= (1 << log_id);
Joe Onorato6fa09a02010-02-26 10:04:23 -0800753 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800754 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700755 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800756
757 case 'B':
Tom Cherryd162f142019-10-24 17:35:26 -0700758 print_binary_ = 1;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800759 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800760
761 case 'f':
Mark Salyzynde022a82017-03-01 08:30:06 -0800762 if ((tail_time == log_time::EPOCH) && !tail_lines) {
Elliott Hughes61b580e2018-06-15 15:16:20 -0700763 tail_time = lastLogTime(optarg);
Mark Salyzynf3555d92015-05-27 07:39:56 -0700764 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800765 // redirect output to a file
Tom Cherryd162f142019-10-24 17:35:26 -0700766 output_file_name_ = optarg;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800767 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800768
Mark Salyzyn1325ebf2016-06-07 13:03:10 -0700769 case 'r':
Tom Cherry6f061e82019-10-29 07:05:24 -0700770 if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800771 error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -r.", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800772 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800773 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800774
Mark Salyzyn1325ebf2016-06-07 13:03:10 -0700775 case 'n':
Tom Cherry6f061e82019-10-29 07:05:24 -0700776 if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800777 error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -n.", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800778 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800779 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800780
Tom Cherry6f061e82019-10-29 07:05:24 -0700781 case 'v':
Elliott Hughes61b580e2018-06-15 15:16:20 -0700782 if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
Tom Cherryd162f142019-10-24 17:35:26 -0700783 show_format_help();
784 return EXIT_SUCCESS;
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700785 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700786 for (const auto& arg : Split(optarg, delimiters)) {
787 int err = SetLogFormat(arg.c_str());
Mark Salyzynb45a1752017-02-28 09:20:31 -0800788 if (err < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800789 error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -v.", arg.c_str());
Mark Salyzynb45a1752017-02-28 09:20:31 -0800790 }
Mark Salyzynb45a1752017-02-28 09:20:31 -0800791 if (err) hasSetLogFormat = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800792 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700793 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800794
795 case 'Q':
bohu94aab862017-02-21 14:31:19 -0800796#define LOGCAT_FILTER "androidboot.logcat="
797#define CONSOLE_PIPE_OPTION "androidboot.consolepipe="
Mark Salyzyn5f606602017-02-10 13:09:07 -0800798#define CONSOLE_OPTION "androidboot.console="
bohu94aab862017-02-21 14:31:19 -0800799#define QEMU_PROPERTY "ro.kernel.qemu"
800#define QEMU_CMDLINE "qemu.cmdline"
Mark Salyzyn5f606602017-02-10 13:09:07 -0800801 // This is a *hidden* option used to start a version of logcat
802 // in an emulated device only. It basically looks for
803 // androidboot.logcat= on the kernel command line. If
804 // something is found, it extracts a log filter and uses it to
bohu94aab862017-02-21 14:31:19 -0800805 // run the program. The logcat output will go to consolepipe if
806 // androiboot.consolepipe (e.g. qemu_pipe) is given, otherwise,
807 // it goes to androidboot.console (e.g. tty)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800808 {
bohu94aab862017-02-21 14:31:19 -0800809 // if not in emulator, exit quietly
810 if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) {
Tom Cherryd162f142019-10-24 17:35:26 -0700811 return EXIT_SUCCESS;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800812 }
Mark Salyzynf3290292017-02-10 13:09:07 -0800813
bohu94aab862017-02-21 14:31:19 -0800814 std::string cmdline = android::base::GetProperty(QEMU_CMDLINE, "");
815 if (cmdline.empty()) {
816 android::base::ReadFileToString("/proc/cmdline", &cmdline);
817 }
818
819 const char* logcatFilter = strstr(cmdline.c_str(), LOGCAT_FILTER);
820 // if nothing found or invalid filters, exit quietly
821 if (!logcatFilter) {
Tom Cherryd162f142019-10-24 17:35:26 -0700822 return EXIT_SUCCESS;
bohu94aab862017-02-21 14:31:19 -0800823 }
824
825 const char* p = logcatFilter + strlen(LOGCAT_FILTER);
Mark Salyzynf3290292017-02-10 13:09:07 -0800826 const char* q = strpbrk(p, " \t\n\r");
827 if (!q) q = p + strlen(p);
828 forceFilters = std::string(p, q);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800829
bohu94aab862017-02-21 14:31:19 -0800830 // redirect our output to the emulator console pipe or console
831 const char* consolePipe =
832 strstr(cmdline.c_str(), CONSOLE_PIPE_OPTION);
Mark Salyzynf3290292017-02-10 13:09:07 -0800833 const char* console =
834 strstr(cmdline.c_str(), CONSOLE_OPTION);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800835
bohu94aab862017-02-21 14:31:19 -0800836 if (consolePipe) {
837 p = consolePipe + strlen(CONSOLE_PIPE_OPTION);
838 } else if (console) {
839 p = console + strlen(CONSOLE_OPTION);
840 } else {
Tom Cherryd162f142019-10-24 17:35:26 -0700841 return EXIT_FAILURE;
bohu94aab862017-02-21 14:31:19 -0800842 }
843
Mark Salyzynf3290292017-02-10 13:09:07 -0800844 q = strpbrk(p, " \t\n\r");
845 int len = q ? q - p : strlen(p);
846 std::string devname = "/dev/" + std::string(p, len);
bohu94aab862017-02-21 14:31:19 -0800847 std::string pipePurpose("pipe:logcat");
848 if (consolePipe) {
849 // example: "qemu_pipe,pipe:logcat"
850 // upon opening of /dev/qemu_pipe, the "pipe:logcat"
851 // string with trailing '\0' should be written to the fd
Chih-Hung Hsiehe5d975c2017-08-03 13:56:49 -0700852 size_t pos = devname.find(',');
bohu94aab862017-02-21 14:31:19 -0800853 if (pos != std::string::npos) {
854 pipePurpose = devname.substr(pos + 1);
855 devname = devname.substr(0, pos);
856 }
857 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800858
Tom Cherryd162f142019-10-24 17:35:26 -0700859 fprintf(stderr, "logcat using %s\n", devname.c_str());
860
861 int fd = open(devname.c_str(), O_WRONLY | O_CLOEXEC);
862 if (fd < 0) {
863 break;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800864 }
Mark Salyzynf3290292017-02-10 13:09:07 -0800865
bohu94aab862017-02-21 14:31:19 -0800866 if (consolePipe) {
867 // need the trailing '\0'
Tom Cherry3e970d42020-08-05 14:01:11 -0700868 if (!WriteFully(fd, pipePurpose.c_str(), pipePurpose.size() + 1)) {
Tom Cherryd162f142019-10-24 17:35:26 -0700869 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 Cherry72a4e082019-12-06 10:25:37 -0800885 error(EXIT_FAILURE, 0, "Option '%s' needs an argument.", argv[optind - 1]);
886 break;
Traian Schiau59763032015-04-10 15:51:39 +0300887
Mark Salyzyne74e51d2017-04-03 09:30:20 -0700888 case 'h':
Tom Cherryd162f142019-10-24 17:35:26 -0700889 show_help();
890 show_format_help();
891 return EXIT_SUCCESS;
Mark Salyzyne74e51d2017-04-03 09:30:20 -0700892
Tom Cherry72a4e082019-12-06 10:25:37 -0800893 case '?':
894 error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind - 1]);
895 break;
896
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800897 default:
Tom Cherry72a4e082019-12-06 10:25:37 -0800898 error(EXIT_FAILURE, 0, "Unknown getopt_long() result '%c'.", c);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800899 }
900 }
901
Tom Cherryd162f142019-10-24 17:35:26 -0700902 if (max_count_ && got_t) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800903 error(EXIT_FAILURE, 0, "Cannot use -m (--max-count) and -t together.");
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700904 }
Tom Cherryd162f142019-10-24 17:35:26 -0700905 if (print_it_anyways_ && (!regex_ || !max_count_)) {
Mark Salyzync9202772016-03-30 09:38:31 -0700906 // One day it would be nice if --print -v color and --regex <expr>
907 // could play with each other and show regex highlighted content.
Tom Cherryd162f142019-10-24 17:35:26 -0700908 fprintf(stderr,
909 "WARNING: "
910 "--print ignored, to be used in combination with\n"
911 " "
912 "--regex <expr> and --max-count <N>\n");
913 print_it_anyways_ = false;
Mark Salyzync9202772016-03-30 09:38:31 -0700914 }
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700915
Tom Cherry6f061e82019-10-29 07:05:24 -0700916 // If no buffers are specified, default to using these buffers.
917 if (id_mask == 0) {
918 id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
919 (1 << LOG_ID_KERNEL);
Joe Onorato6fa09a02010-02-26 10:04:23 -0800920 }
921
Tom Cherryd162f142019-10-24 17:35:26 -0700922 if (log_rotate_size_kb_ != 0 && !output_file_name_) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800923 error(EXIT_FAILURE, 0, "-r requires -f as well.");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800924 }
925
Tom Cherryd162f142019-10-24 17:35:26 -0700926 if (setId != 0) {
927 if (!output_file_name_) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800928 error(EXIT_FAILURE, 0, "--id='%s' requires -f as well.", setId);
Mark Salyzyn02687e72016-08-03 14:20:41 -0700929 }
930
Tom Cherryd162f142019-10-24 17:35:26 -0700931 std::string file_name = StringPrintf("%s.id", output_file_name_);
Mark Salyzyn02687e72016-08-03 14:20:41 -0700932 std::string file;
933 bool file_ok = android::base::ReadFileToString(file_name, &file);
Mark Salyzyn5f606602017-02-10 13:09:07 -0800934 android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
935 getuid(), getgid());
Mark Salyzynde022a82017-03-01 08:30:06 -0800936 if (!file_ok || !file.compare(setId)) setId = nullptr;
Mark Salyzyn02687e72016-08-03 14:20:41 -0700937 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800938
Mark Salyzynde022a82017-03-01 08:30:06 -0800939 if (!hasSetLogFormat) {
Tom Cherryd162f142019-10-24 17:35:26 -0700940 const char* logFormat = getenv("ANDROID_PRINTF_LOG");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800941
Mark Salyzynde022a82017-03-01 08:30:06 -0800942 if (!!logFormat) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700943 for (const auto& arg : Split(logFormat, delimiters)) {
944 int err = SetLogFormat(arg.c_str());
Mark Salyzynb45a1752017-02-28 09:20:31 -0800945 // environment should not cause crash of logcat
Tom Cherryd162f142019-10-24 17:35:26 -0700946 if (err < 0) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700947 fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
Mark Salyzynb45a1752017-02-28 09:20:31 -0800948 }
Mark Salyzynb45a1752017-02-28 09:20:31 -0800949 if (err > 0) hasSetLogFormat = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800950 }
Mark Salyzynb45a1752017-02-28 09:20:31 -0800951 }
952 if (!hasSetLogFormat) {
Tom Cherryd162f142019-10-24 17:35:26 -0700953 SetLogFormat("threadtime");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800954 }
955 }
956
Mark Salyzynf3290292017-02-10 13:09:07 -0800957 if (forceFilters.size()) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700958 int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800959 if (err < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800960 error(EXIT_FAILURE, 0, "Invalid filter expression in logcat args.");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800961 }
Elliott Hughes61b580e2018-06-15 15:16:20 -0700962 } else if (argc == optind) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800963 // Add from environment variable
Tom Cherryd162f142019-10-24 17:35:26 -0700964 const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800965
Mark Salyzynde022a82017-03-01 08:30:06 -0800966 if (!!env_tags_orig) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700967 int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800968
Mark Salyzyn95132e92013-11-22 10:55:48 -0800969 if (err < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800970 error(EXIT_FAILURE, 0, "Invalid filter expression in ANDROID_LOG_TAGS.");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800971 }
972 }
973 } else {
974 // Add from commandline
Elliott Hughes61b580e2018-06-15 15:16:20 -0700975 for (int i = optind ; i < argc ; i++) {
Tom Cherry6f061e82019-10-29 07:05:24 -0700976 int err = android_log_addFilterString(logformat_.get(), argv[i]);
Mark Salyzyn95132e92013-11-22 10:55:48 -0800977 if (err < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800978 error(EXIT_FAILURE, 0, "Invalid filter expression '%s'.", argv[i]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800979 }
980 }
981 }
982
Tom Cherry9156c532019-11-14 08:56:39 -0800983 if (mode & ANDROID_LOG_PSTORE) {
Tom Cherryc30a3ee2019-12-04 14:37:38 -0800984 if (output_file_name_) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800985 error(EXIT_FAILURE, 0, "-c is ambiguous with both -f and -L specified.");
Tom Cherryc30a3ee2019-12-04 14:37:38 -0800986 }
987 if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800988 error(EXIT_FAILURE, 0, "-L is incompatible with -g/-G, -S, and -p/-P.");
Tom Cherryc30a3ee2019-12-04 14:37:38 -0800989 }
Tom Cherry9156c532019-11-14 08:56:39 -0800990 if (clearLog) {
991 unlink("/sys/fs/pstore/pmsg-ramoops-0");
992 return EXIT_SUCCESS;
993 }
Tom Cherryc30a3ee2019-12-04 14:37:38 -0800994 }
995
996 if (output_file_name_) {
Tom Cherry9156c532019-11-14 08:56:39 -0800997 if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800998 error(EXIT_FAILURE, 0, "-f is incompatible with -g/-G, -S, and -p/-P.");
Tom Cherryc30a3ee2019-12-04 14:37:38 -0800999 }
1000
1001 if (clearLog || setId) {
1002 int max_rotation_count_digits =
1003 max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
1004
1005 for (int i = max_rotated_logs_; i >= 0; --i) {
1006 std::string file;
1007
1008 if (!i) {
1009 file = output_file_name_;
1010 } else {
1011 file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
1012 }
1013
1014 int err = unlink(file.c_str());
1015
1016 if (err < 0 && errno != ENOENT) {
1017 fprintf(stderr, "failed to delete log file '%s': %s\n", file.c_str(),
1018 strerror(errno));
1019 }
1020 }
1021 }
1022
1023 if (clearLog) {
1024 return EXIT_SUCCESS;
Tom Cherry9156c532019-11-14 08:56:39 -08001025 }
1026 }
1027
Tom Cherry6f061e82019-10-29 07:05:24 -07001028 std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
1029 nullptr, &android_logger_list_free};
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001030 if (tail_time != log_time::EPOCH) {
Tom Cherry6f061e82019-10-29 07:05:24 -07001031 logger_list.reset(android_logger_list_alloc_time(mode, tail_time, pid));
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001032 } else {
Tom Cherry6f061e82019-10-29 07:05:24 -07001033 logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001034 }
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001035 // We have three orthogonal actions below to clear, set log size and
1036 // get log size. All sharing the same iteration loop.
Tom Cherry6f061e82019-10-29 07:05:24 -07001037 std::vector<std::string> open_device_failures;
1038 std::vector<std::string> clear_failures;
1039 std::vector<std::string> set_size_failures;
1040 std::vector<std::string> get_size_failures;
1041
1042 for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
1043 if (!(id_mask & (1 << i))) continue;
1044 const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
1045
1046 auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
1047 if (logger == nullptr) {
1048 ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001049 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001050 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001051
Tom Cherryc30a3ee2019-12-04 14:37:38 -08001052 if (clearLog) {
1053 if (android_logger_clear(logger)) {
Tom Cherry6f061e82019-10-29 07:05:24 -07001054 ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
Joe Onorato6fa09a02010-02-26 10:04:23 -08001055 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001056 }
1057
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001058 if (setLogSize) {
Tom Cherry6f061e82019-10-29 07:05:24 -07001059 if (android_logger_set_log_size(logger, setLogSize)) {
1060 ReportErrorName(buffer_name, security_buffer_selected, &set_size_failures);
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001061 }
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001062 }
1063
Joe Onorato6fa09a02010-02-26 10:04:23 -08001064 if (getLogSize) {
Tom Cherry6f061e82019-10-29 07:05:24 -07001065 long size = android_logger_get_log_size(logger);
1066 long readable = android_logger_get_log_readable_size(logger);
Tom Cherry06e111a2020-08-05 11:22:44 -07001067 long consumed = android_logger_get_log_consumed_size(logger);
Joe Onorato6fa09a02010-02-26 10:04:23 -08001068
Tom Cherry6f061e82019-10-29 07:05:24 -07001069 if (size < 0 || readable < 0) {
1070 ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001071 } else {
Wei Wangc27d4812018-09-05 11:05:57 -07001072 auto size_format = format_of_size(size);
1073 auto readable_format = format_of_size(readable);
Tom Cherry06e111a2020-08-05 11:22:44 -07001074 auto consumed_format = format_of_size(consumed);
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001075 std::string str = android::base::StringPrintf(
Tom Cherry06e111a2020-08-05 11:22:44 -07001076 "%s: ring buffer is %lu %sB (%lu %sB consumed, %lu %sB readable),"
Tom Cherry6f061e82019-10-29 07:05:24 -07001077 " max entry is %d B, max payload is %d B\n",
Tom Cherry06e111a2020-08-05 11:22:44 -07001078 buffer_name, size_format.first, size_format.second, consumed_format.first,
1079 consumed_format.second, readable_format.first, readable_format.second,
1080 (int)LOGGER_ENTRY_MAX_LEN, (int)LOGGER_ENTRY_MAX_PAYLOAD);
Tom Cherry3e970d42020-08-05 14:01:11 -07001081 if (!WriteFully(output_fd_, str.data(), str.length())) {
1082 error(EXIT_FAILURE, errno, "Failed to write to output fd");
1083 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001084 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001085 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001086 }
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001087
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001088 // report any errors in the above loop and exit
Tom Cherry6f061e82019-10-29 07:05:24 -07001089 if (!open_device_failures.empty()) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001090 error(EXIT_FAILURE, 0, "Unable to open log device%s '%s'.",
1091 open_device_failures.size() > 1 ? "s" : "", Join(open_device_failures, ",").c_str());
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001092 }
Tom Cherry6f061e82019-10-29 07:05:24 -07001093 if (!clear_failures.empty()) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001094 error(EXIT_FAILURE, 0, "failed to clear the '%s' log%s.", Join(clear_failures, ",").c_str(),
1095 clear_failures.size() > 1 ? "s" : "");
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001096 }
Tom Cherry6f061e82019-10-29 07:05:24 -07001097 if (!set_size_failures.empty()) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001098 error(EXIT_FAILURE, 0, "failed to set the '%s' log size%s.",
1099 Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001100 }
Tom Cherry6f061e82019-10-29 07:05:24 -07001101 if (!get_size_failures.empty()) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001102 error(EXIT_FAILURE, 0, "failed to get the readable '%s' log size%s.",
1103 Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001104 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001105
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001106 if (setPruneList) {
Traian Schiau59763032015-04-10 15:51:39 +03001107 size_t len = strlen(setPruneList);
Tom Cherryed860ff2019-12-06 11:01:51 -08001108 if (android_logger_set_prune_list(logger_list.get(), setPruneList, len)) {
1109 error(EXIT_FAILURE, 0, "Failed to set the prune list.");
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001110 }
Tom Cherryd162f142019-10-24 17:35:26 -07001111 return EXIT_SUCCESS;
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001112 }
1113
Mark Salyzyn1c950472014-04-01 17:19:47 -07001114 if (printStatistics || getPruneList) {
Tom Cherrye17b4f62019-12-06 13:33:11 -08001115 std::string buf(8192, '\0');
1116 size_t ret_length = 0;
1117 int retry = 32;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001118
Tom Cherrye17b4f62019-12-06 13:33:11 -08001119 for (; retry >= 0; --retry) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001120 if (getPruneList) {
Tom Cherrye17b4f62019-12-06 13:33:11 -08001121 android_logger_get_prune_list(logger_list.get(), buf.data(), buf.size());
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001122 } else {
Tom Cherrye17b4f62019-12-06 13:33:11 -08001123 android_logger_get_statistics(logger_list.get(), buf.data(), buf.size());
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001124 }
Tom Cherrye17b4f62019-12-06 13:33:11 -08001125
1126 ret_length = atol(buf.c_str());
1127 if (ret_length < 3) {
1128 error(EXIT_FAILURE, 0, "Failed to read data.");
1129 }
1130
1131 if (ret_length < buf.size()) {
Mark Salyzyn34facab2014-02-06 14:48:50 -08001132 break;
1133 }
Tom Cherrye17b4f62019-12-06 13:33:11 -08001134
1135 buf.resize(ret_length + 1);
Mark Salyzyn34facab2014-02-06 14:48:50 -08001136 }
1137
Tom Cherrye17b4f62019-12-06 13:33:11 -08001138 if (retry < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001139 error(EXIT_FAILURE, 0, "Failed to read data.");
Mark Salyzyn34facab2014-02-06 14:48:50 -08001140 }
1141
Tom Cherrye17b4f62019-12-06 13:33:11 -08001142 buf.resize(ret_length);
1143 if (buf.back() == '\f') {
1144 buf.pop_back();
Mark Salyzyn34facab2014-02-06 14:48:50 -08001145 }
1146
Tom Cherrye17b4f62019-12-06 13:33:11 -08001147 // Remove the byte count prefix
1148 const char* cp = buf.c_str();
1149 while (isdigit(*cp)) ++cp;
1150 if (*cp == '\n') ++cp;
1151
1152 size_t len = strlen(cp);
Tom Cherry3e970d42020-08-05 14:01:11 -07001153 if (!WriteFully(output_fd_, cp, len)) {
1154 error(EXIT_FAILURE, errno, "Failed to write to output fd");
1155 }
Tom Cherryd162f142019-10-24 17:35:26 -07001156 return EXIT_SUCCESS;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001157 }
1158
Tom Cherryd162f142019-10-24 17:35:26 -07001159 if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001160
Tom Cherryd162f142019-10-24 17:35:26 -07001161 SetupOutputAndSchedulingPolicy(!(mode & ANDROID_LOG_NONBLOCK));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001162
Tom Cherryd162f142019-10-24 17:35:26 -07001163 while (!max_count_ || print_count_ < max_count_) {
Mark Salyzyn95132e92013-11-22 10:55:48 -08001164 struct log_msg log_msg;
Tom Cherry6f061e82019-10-29 07:05:24 -07001165 int ret = android_logger_list_read(logger_list.get(), &log_msg);
Mark Salyzynde022a82017-03-01 08:30:06 -08001166 if (!ret) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001167 error(EXIT_FAILURE, 0, R"init(Unexpected EOF!
Tom Cherry41697322019-11-21 10:31:06 -08001168
Tom Cherry26d712e2020-02-14 10:01:57 -08001169This means that either the device shut down, logd crashed, or this instance of logcat was unable to read log
Tom Cherry41697322019-11-21 10:31:06 -08001170messages as quickly as they were being produced.
1171
Tom Cherry72a4e082019-12-06 10:25:37 -08001172If you have enabled significant logging, look into using the -G option to increase log buffer sizes.)init");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001173 }
1174
1175 if (ret < 0) {
Mark Salyzynde022a82017-03-01 08:30:06 -08001176 if (ret == -EAGAIN) break;
Mark Salyzyn95132e92013-11-22 10:55:48 -08001177
1178 if (ret == -EIO) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001179 error(EXIT_FAILURE, 0, "Unexpected EOF!");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001180 }
1181 if (ret == -EINVAL) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001182 error(EXIT_FAILURE, 0, "Unexpected length.");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001183 }
Tom Cherry72a4e082019-12-06 10:25:37 -08001184 error(EXIT_FAILURE, errno, "Logcat read failure");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001185 }
1186
Tom Cherry6f061e82019-10-29 07:05:24 -07001187 if (log_msg.id() > LOG_ID_MAX) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001188 error(EXIT_FAILURE, 0, "Unexpected log id (%d) over LOG_ID_MAX (%d).", log_msg.id(),
1189 LOG_ID_MAX);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001190 }
1191
Tom Cherry9291f0f2020-04-13 10:07:53 -07001192 if (!uids.empty() && uids.count(log_msg.entry.uid) == 0) {
1193 continue;
1194 }
1195
Tom Cherry6f061e82019-10-29 07:05:24 -07001196 PrintDividers(log_msg.id(), printDividers);
1197
Tom Cherryd162f142019-10-24 17:35:26 -07001198 if (print_binary_) {
Tom Cherry3e970d42020-08-05 14:01:11 -07001199 if (!WriteFully(output_fd_, &log_msg, log_msg.len())) {
1200 error(EXIT_FAILURE, errno, "Failed to write to output fd");
1201 }
Mark Salyzyn95132e92013-11-22 10:55:48 -08001202 } else {
Tom Cherry6f061e82019-10-29 07:05:24 -07001203 ProcessBuffer(&log_msg);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001204 }
1205 }
Tom Cherryd162f142019-10-24 17:35:26 -07001206 return EXIT_SUCCESS;
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001207}
1208
Tom Cherry98c6c332019-10-30 13:51:03 -07001209int main(int argc, char** argv) {
Tom Cherryd162f142019-10-24 17:35:26 -07001210 Logcat logcat;
1211 return logcat.Run(argc, argv);
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001212}