blob: 0056c809ba6eae53f48760de730f51272ae581e6 [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;
67
Tom Cherryd162f142019-10-24 17:35:26 -070068class Logcat {
69 public:
Tom Cherryd162f142019-10-24 17:35:26 -070070 int Run(int argc, char** argv);
Mark Salyzync0cf90d2017-02-10 13:09:07 -080071
Tom Cherryd162f142019-10-24 17:35:26 -070072 private:
73 void RotateLogs();
Tom Cherry6f061e82019-10-29 07:05:24 -070074 void ProcessBuffer(struct log_msg* buf);
75 void PrintDividers(log_id_t log_id, bool print_dividers);
Tom Cherryd162f142019-10-24 17:35:26 -070076 void SetupOutputAndSchedulingPolicy(bool blocking);
77 int SetLogFormat(const char* format_string);
78
Tom Cherry6f061e82019-10-29 07:05:24 -070079 // Used for all options
Tom Cherryd162f142019-10-24 17:35:26 -070080 android::base::unique_fd output_fd_{dup(STDOUT_FILENO)};
81 std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
82 android_log_format_new(), &android_log_format_free};
Tom Cherry6f061e82019-10-29 07:05:24 -070083
84 // For logging to a file and log rotation
Tom Cherryd162f142019-10-24 17:35:26 -070085 const char* output_file_name_ = nullptr;
Tom Cherry6f061e82019-10-29 07:05:24 -070086 size_t log_rotate_size_kb_ = 0; // 0 means "no log rotation"
87 size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
Tom Cherryd162f142019-10-24 17:35:26 -070088 size_t out_byte_count_ = 0;
Tom Cherry6f061e82019-10-29 07:05:24 -070089
90 // For binary log buffers
Tom Cherryd162f142019-10-24 17:35:26 -070091 int print_binary_ = 0;
Tom Cherryd162f142019-10-24 17:35:26 -070092 std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
93 nullptr, &android_closeEventTagMap};
Tom Cherryd162f142019-10-24 17:35:26 -070094 bool has_opened_event_tag_map_ = false;
Tom Cherry6f061e82019-10-29 07:05:24 -070095
96 // For the related --regex, --max-count, --print
97 std::unique_ptr<std::regex> regex_;
98 size_t max_count_ = 0; // 0 means "infinite"
99 size_t print_count_ = 0;
100 bool print_it_anyways_ = false;
101
102 // For PrintDividers()
103 log_id_t last_printed_id_ = LOG_ID_MAX;
104 bool printed_start_[LOG_ID_MAX] = {};
105
106 bool debug_ = false;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800107};
108
Jaegeuk Kim5327d932019-07-04 18:09:38 -0700109#ifndef F2FS_IOC_SET_PIN_FILE
110#define F2FS_IOCTL_MAGIC 0xf5
111#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
112#endif
113
114static int openLogFile(const char* pathname, size_t sizeKB) {
Mike Maa7fb0952020-01-17 18:01:03 -0800115 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 -0700116 if (fd < 0) {
117 return fd;
118 }
119
120 // no need to check errors
121 __u32 set = 1;
122 ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
123 fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, (sizeKB << 10));
124 return fd;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800125}
126
Jaegeuk Kim2e5b7c42020-04-23 08:28:35 -0700127static void closeLogFile(const char* pathname) {
128 int fd = open(pathname, O_WRONLY | O_CLOEXEC);
129 if (fd == -1) {
130 return;
131 }
132
133 // no need to check errors
134 __u32 set = 0;
135 ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
136 close(fd);
137}
138
Tom Cherryd162f142019-10-24 17:35:26 -0700139void Logcat::RotateLogs() {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800140 // Can't rotate logs if we're not outputting to a file
Tom Cherryd162f142019-10-24 17:35:26 -0700141 if (!output_file_name_) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800142
Tom Cherryd162f142019-10-24 17:35:26 -0700143 output_fd_.reset();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800144
Mark Salyzyn5f606602017-02-10 13:09:07 -0800145 // Compute the maximum number of digits needed to count up to
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800146 // maxRotatedLogs in decimal. eg:
147 // maxRotatedLogs == 30
Mark Salyzyn5f606602017-02-10 13:09:07 -0800148 // -> log10(30) == 1.477
149 // -> maxRotationCountDigits == 2
Tom Cherryd162f142019-10-24 17:35:26 -0700150 int max_rotation_count_digits =
151 max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
Aristidis Papaioannoueba73442014-10-16 22:19:55 -0700152
Tom Cherryd162f142019-10-24 17:35:26 -0700153 for (int i = max_rotated_logs_; i > 0; i--) {
154 std::string file1 =
155 StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800156
Mark Salyzyn5b1a5382016-08-03 14:20:41 -0700157 std::string file0;
Mark Salyzynde022a82017-03-01 08:30:06 -0800158 if (!(i - 1)) {
Tom Cherryd162f142019-10-24 17:35:26 -0700159 file0 = output_file_name_;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800160 } else {
Tom Cherryd162f142019-10-24 17:35:26 -0700161 file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800162 }
163
Mark Salyzynde022a82017-03-01 08:30:06 -0800164 if (!file0.length() || !file1.length()) {
Traian Schiau59763032015-04-10 15:51:39 +0300165 perror("while rotating log files");
166 break;
167 }
168
Jaegeuk Kim2e5b7c42020-04-23 08:28:35 -0700169 closeLogFile(file0.c_str());
170
Tom Cherryd162f142019-10-24 17:35:26 -0700171 int err = rename(file0.c_str(), file1.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800172
173 if (err < 0 && errno != ENOENT) {
174 perror("while rotating log files");
175 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800176 }
177
Tom Cherryd162f142019-10-24 17:35:26 -0700178 output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800179
Tom Cherryd162f142019-10-24 17:35:26 -0700180 if (!output_fd_.ok()) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800181 error(EXIT_FAILURE, errno, "Couldn't open output file");
Mark Salyzyne3d0c962017-02-17 13:15:51 -0800182 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800183
Tom Cherryd162f142019-10-24 17:35:26 -0700184 out_byte_count_ = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800185}
186
Tom Cherry6f061e82019-10-29 07:05:24 -0700187void Logcat::ProcessBuffer(struct log_msg* buf) {
Mathias Agopian50844522010-03-17 16:10:26 -0700188 int bytesWritten = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800189 int err;
190 AndroidLogEntry entry;
191 char binaryMsgBuf[1024];
192
Tom Cherry6f061e82019-10-29 07:05:24 -0700193 bool is_binary =
194 buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
195
196 if (is_binary) {
Tom Cherryd162f142019-10-24 17:35:26 -0700197 if (!event_tag_map_ && !has_opened_event_tag_map_) {
198 event_tag_map_.reset(android_openEventTagMap(nullptr));
199 has_opened_event_tag_map_ = true;
Mark Salyzyn9421b0c2015-02-26 14:33:35 -0800200 }
Tom Cherryd162f142019-10-24 17:35:26 -0700201 err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
Tom Cherry441054a2019-10-15 16:53:11 -0700202 binaryMsgBuf, sizeof(binaryMsgBuf));
Mark Salyzyn5f606602017-02-10 13:09:07 -0800203 // printf(">>> pri=%d len=%d msg='%s'\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800204 // entry.priority, entry.messageLen, entry.message);
205 } else {
Tom Cherry441054a2019-10-15 16:53:11 -0700206 err = android_log_processLogBuffer(&buf->entry, &entry);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800207 }
Tom Cherryd162f142019-10-24 17:35:26 -0700208 if (err < 0 && !debug_) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800209
Tom Cherryd162f142019-10-24 17:35:26 -0700210 if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
211 entry.priority)) {
212 bool match = !regex_ ||
213 std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800214
Tom Cherryd162f142019-10-24 17:35:26 -0700215 print_count_ += match;
216 if (match || print_it_anyways_) {
217 bytesWritten = android_log_printLogLine(logformat_.get(), output_fd_.get(), &entry);
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700218
Mark Salyzync9202772016-03-30 09:38:31 -0700219 if (bytesWritten < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800220 error(EXIT_FAILURE, 0, "Output error.");
Mark Salyzync9202772016-03-30 09:38:31 -0700221 }
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800222 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800223 }
224
Tom Cherryd162f142019-10-24 17:35:26 -0700225 out_byte_count_ += bytesWritten;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800226
Tom Cherryd162f142019-10-24 17:35:26 -0700227 if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
228 RotateLogs();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800229 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800230}
231
Tom Cherry6f061e82019-10-29 07:05:24 -0700232void Logcat::PrintDividers(log_id_t log_id, bool print_dividers) {
233 if (log_id == last_printed_id_ || print_binary_) {
234 return;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800235 }
Tom Cherry6f061e82019-10-29 07:05:24 -0700236 if (!printed_start_[log_id] || print_dividers) {
237 if (dprintf(output_fd_.get(), "--------- %s %s\n",
238 printed_start_[log_id] ? "switch to" : "beginning of",
239 android_log_id_to_name(log_id)) < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800240 error(EXIT_FAILURE, errno, "Output error");
Tom Cherry6f061e82019-10-29 07:05:24 -0700241 }
242 }
243 last_printed_id_ = log_id;
244 printed_start_[log_id] = true;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800245}
246
Tom Cherryd162f142019-10-24 17:35:26 -0700247void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
248 if (!output_file_name_) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800249
Mark Salyzynad5e4112016-08-04 07:53:52 -0700250 if (blocking) {
251 // Lower priority and set to batch scheduling if we are saving
252 // the logs into files and taking continuous content.
Tom Cherryd162f142019-10-24 17:35:26 -0700253 if (set_sched_policy(0, SP_BACKGROUND) < 0) {
254 fprintf(stderr, "failed to set background scheduling policy\n");
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700255 }
256
Tom Cherryd162f142019-10-24 17:35:26 -0700257 struct sched_param param = {};
Mark Salyzyn5f606602017-02-10 13:09:07 -0800258 if (sched_setscheduler((pid_t)0, SCHED_BATCH, &param) < 0) {
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700259 fprintf(stderr, "failed to set to batch scheduler\n");
260 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800261
Tom Cherryd162f142019-10-24 17:35:26 -0700262 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
263 fprintf(stderr, "failed set to priority\n");
Riley Andrewsaede9892015-06-08 23:36:34 -0700264 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800265 }
Mark Salyzynad5e4112016-08-04 07:53:52 -0700266
Tom Cherryd162f142019-10-24 17:35:26 -0700267 output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
Mark Salyzynad5e4112016-08-04 07:53:52 -0700268
Tom Cherryd162f142019-10-24 17:35:26 -0700269 if (!output_fd_.ok()) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800270 error(EXIT_FAILURE, errno, "Couldn't open output file");
Mark Salyzynad5e4112016-08-04 07:53:52 -0700271 }
272
273 struct stat statbuf;
Tom Cherryd162f142019-10-24 17:35:26 -0700274 if (fstat(output_fd_.get(), &statbuf) == -1) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800275 error(EXIT_FAILURE, errno, "Couldn't get output file stat");
Mark Salyzynad5e4112016-08-04 07:53:52 -0700276 }
277
Mark Salyzyn5f606602017-02-10 13:09:07 -0800278 if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800279 error(EXIT_FAILURE, 0, "Invalid output file stat.");
Mark Salyzynad5e4112016-08-04 07:53:52 -0700280 }
281
Tom Cherryd162f142019-10-24 17:35:26 -0700282 out_byte_count_ = statbuf.st_size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800283}
284
Mark Salyzyn5f606602017-02-10 13:09:07 -0800285// clang-format off
Tom Cherryd162f142019-10-24 17:35:26 -0700286static void show_help() {
287 const char* cmd = getprogname();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800288
Tom Cherryd162f142019-10-24 17:35:26 -0700289 fprintf(stderr, "Usage: %s [options] [filterspecs]\n", cmd);
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800290
Tom Cherry41697322019-11-21 10:31:06 -0800291 fprintf(stderr, R"init(
292General options:
293 -b, --buffer=<buffer> Request alternate ring buffer(s):
294 main system radio events crash default all
295 Additionally, 'kernel' for userdebug and eng builds, and
296 'security' for Device Owner installations.
297 Multiple -b parameters or comma separated list of buffers are
298 allowed. Buffers are interleaved.
299 Default -b main,system,crash,kernel.
300 -L, --last Dump logs from prior to last reboot from pstore.
301 -c, --clear Clear (flush) the entire log and exit.
302 if -f is specified, clear the specified file and its related rotated
303 log files instead.
304 if -L is specified, clear pstore log instead.
305 -d Dump the log and then exit (don't block).
306 --pid=<pid> Only print logs from the given pid.
307 --wrap Sleep for 2 hours or when buffer about to wrap whichever
308 comes first. Improves efficiency of polling by providing
309 an about-to-wrap wakeup.
310
311Formatting:
312 -v, --format=<format> Sets log print format verb and adverbs, where <format> is one of:
313 brief help long process raw tag thread threadtime time
314 Modifying adverbs can be added:
315 color descriptive epoch monotonic printable uid usec UTC year zone
316 Multiple -v parameters or comma separated list of format and format
317 modifiers are allowed.
318 -D, --dividers Print dividers between each log buffer.
319 -B, --binary Output the log in binary.
320
321Outfile files:
322 -f, --file=<file> Log to file instead of stdout.
323 -r, --rotate-kbytes=<n> Rotate log every <n> kbytes. Requires -f option.
324 -n, --rotate-count=<count> Sets max number of rotated logs to <count>, default 4.
325 --id=<id> If the signature <id> for logging to file changes, then clear the
326 associated files and continue.
327
328Logd control:
329 These options send a control message to the logd daemon on device, print its return message if
330 applicable, then exit. They are incompatible with -L, as these attributes do not apply to pstore.
331 -g, --buffer-size Get the size of the ring buffers within logd.
332 -G, --buffer-size=<size> Set size of a ring buffer in logd. May suffix with K or M.
333 This can individually control each buffer's size with -b.
334 -S, --statistics Output statistics.
335 --pid can be used to provide pid specific stats.
336 -p, --prune Print prune white and ~black list. Service is specified as UID,
337 UID/PID or /PID. Weighed for quicker pruning if prefix with ~,
338 otherwise weighed for longevity if unadorned. All other pruning
339 activity is oldest first. Special case ~! represents an automatic
340 quicker pruning for the noisiest UID as determined by the current
341 statistics.
342 -P, --prune='<list> ...' Set prune white and ~black list, using same format as listed above.
343 Must be quoted.
344
345Filtering:
346 -s Set default filter to silent. Equivalent to filterspec '*:S'
347 -e, --regex=<expr> Only print lines where the log message matches <expr> where <expr> is
348 an ECMAScript regular expression.
349 -m, --max-count=<count> Quit after printing <count> lines. This is meant to be paired with
350 --regex, but will work on its own.
351 --print This option is only applicable when --regex is set and only useful if
352 --max-count is also provided.
353 With --print, logcat will print all messages even if they do not
354 match the regex. Logcat will quit after printing the max-count number
355 of lines that match the regex.
356 -t <count> Print only the most recent <count> lines (implies -d).
357 -t '<time>' Print the lines since specified time (implies -d).
358 -T <count> Print only the most recent <count> lines (does not imply -d).
359 -T '<time>' Print the lines since specified time (not imply -d).
360 count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
361 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format.
Tom Cherry9291f0f2020-04-13 10:07:53 -0700362 --uid=<uids> Only display log messages from UIDs present in the comma separate list
363 <uids>. No name look-up is performed, so UIDs must be provided as
364 numeric values. This option is only useful for the 'root', 'log', and
365 'system' users since only those users can view logs from other users.
Tom Cherry41697322019-11-21 10:31:06 -0800366)init");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800367
Tom Cherryd162f142019-10-24 17:35:26 -0700368 fprintf(stderr, "\nfilterspecs are a series of \n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800369 " <tag>[:priority]\n\n"
370 "where <tag> is a log component tag (or * for all) and priority is:\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700371 " V Verbose (default for <tag>)\n"
372 " D Debug (default for '*')\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800373 " I Info\n"
374 " W Warn\n"
375 " E Error\n"
376 " F Fatal\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700377 " S Silent (suppress all output)\n"
378 "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
379 "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
380 "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
381 "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
382 "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
Mark Salyzyn649fc602014-09-16 09:15:15 -0700383 "or defaults to \"threadtime\"\n\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800384}
385
Tom Cherryd162f142019-10-24 17:35:26 -0700386static void show_format_help() {
387 fprintf(stderr,
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700388 "-v <format>, --format=<format> options:\n"
389 " Sets log print format verb and adverbs, where <format> is:\n"
390 " brief long process raw tag thread threadtime time\n"
391 " and individually flagged modifying adverbs can be added:\n"
392 " color descriptive epoch monotonic printable uid usec UTC year zone\n"
393 "\nSingle format verbs:\n"
394 " brief — Display priority/tag and PID of the process issuing the message.\n"
395 " long — Display all metadata fields, separate messages with blank lines.\n"
396 " process — Display PID only.\n"
397 " raw — Display the raw log message, with no other metadata fields.\n"
398 " tag — Display the priority/tag only.\n"
Mark Salyzync74f8d92017-05-15 13:40:33 -0700399 " thread — Display priority, PID and TID of process issuing the message.\n"
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700400 " threadtime — Display the date, invocation time, priority, tag, and the PID\n"
401 " and TID of the thread issuing the message. (the default format).\n"
402 " time — Display the date, invocation time, priority/tag, and PID of the\n"
403 " process issuing the message.\n"
404 "\nAdverb modifiers can be used in combination:\n"
405 " color — Display in highlighted color to match priority. i.e. \x1B[38;5;231mVERBOSE\n"
406 " \x1B[38;5;75mDEBUG \x1B[38;5;40mINFO \x1B[38;5;166mWARNING \x1B[38;5;196mERROR FATAL\x1B[0m\n"
407 " descriptive — events logs only, descriptions from event-log-tags database.\n"
408 " epoch — Display time as seconds since Jan 1 1970.\n"
409 " monotonic — Display time as cpu seconds since last boot.\n"
410 " printable — Ensure that any binary logging content is escaped.\n"
411 " uid — If permitted, display the UID or Android ID of logged process.\n"
412 " usec — Display time down the microsecond precision.\n"
413 " UTC — Display time as UTC.\n"
414 " year — Add the year to the displayed time.\n"
415 " zone — Add the local timezone to the displayed time.\n"
416 " \"<zone>\" — Print using this public named timezone (experimental).\n\n"
417 );
418}
Mark Salyzyn5f606602017-02-10 13:09:07 -0800419// clang-format on
Mark Salyzyn4fd05072016-10-18 11:30:11 -0700420
Tom Cherryd162f142019-10-24 17:35:26 -0700421int Logcat::SetLogFormat(const char* format_string) {
422 AndroidLogPrintFormat format = android_log_formatFromString(format_string);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800423
Mark Salyzynde022a82017-03-01 08:30:06 -0800424 // invalid string?
425 if (format == FORMAT_OFF) return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800426
Tom Cherryd162f142019-10-24 17:35:26 -0700427 return android_log_setPrintFormat(logformat_.get(), format);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800428}
429
Wei Wangc27d4812018-09-05 11:05:57 -0700430static std::pair<unsigned long, const char*> format_of_size(unsigned long value) {
431 static const char multipliers[][3] = {{""}, {"Ki"}, {"Mi"}, {"Gi"}};
432 size_t i;
Mark Salyzyn671e3432014-05-06 07:34:59 -0700433 for (i = 0;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800434 (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
435 value /= 1024, ++i)
436 ;
Wei Wangc27d4812018-09-05 11:05:57 -0700437 return std::make_pair(value, multipliers[i]);
Mark Salyzyn671e3432014-05-06 07:34:59 -0700438}
439
Mark Salyzyn5f606602017-02-10 13:09:07 -0800440static char* parseTime(log_time& t, const char* cp) {
441 char* ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
Mark Salyzynde022a82017-03-01 08:30:06 -0800442 if (ep) return ep;
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700443 ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
Mark Salyzynde022a82017-03-01 08:30:06 -0800444 if (ep) return ep;
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700445 return t.strptime(cp, "%s.%q");
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700446}
Mark Salyzynf3555d92015-05-27 07:39:56 -0700447
Mark Salyzyn31961062016-08-04 07:43:46 -0700448// Find last logged line in <outputFileName>, or <outputFileName>.1
Mark Salyzyne9ade172017-03-02 15:09:41 -0800449static log_time lastLogTime(const char* outputFileName) {
Mark Salyzynf3555d92015-05-27 07:39:56 -0700450 log_time retval(log_time::EPOCH);
Mark Salyzynde022a82017-03-01 08:30:06 -0800451 if (!outputFileName) return retval;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700452
Mark Salyzynf3555d92015-05-27 07:39:56 -0700453 std::string directory;
Mark Salyzyne9ade172017-03-02 15:09:41 -0800454 const char* file = strrchr(outputFileName, '/');
Mark Salyzynf3555d92015-05-27 07:39:56 -0700455 if (!file) {
456 directory = ".";
457 file = outputFileName;
458 } else {
Mark Salyzyne9ade172017-03-02 15:09:41 -0800459 directory = std::string(outputFileName, file - outputFileName);
Mark Salyzynf3555d92015-05-27 07:39:56 -0700460 ++file;
461 }
Mark Salyzync18c2132016-04-01 07:52:20 -0700462
Mark Salyzyn5f606602017-02-10 13:09:07 -0800463 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()),
464 closedir);
Mark Salyzynde022a82017-03-01 08:30:06 -0800465 if (!dir.get()) return retval;
Mark Salyzync18c2132016-04-01 07:52:20 -0700466
Tom Cherryf2c27462020-04-08 14:36:05 -0700467 log_time now(CLOCK_REALTIME);
Mark Salyzync18c2132016-04-01 07:52:20 -0700468
Mark Salyzynf3555d92015-05-27 07:39:56 -0700469 size_t len = strlen(file);
470 log_time modulo(0, NS_PER_SEC);
Mark Salyzyn5f606602017-02-10 13:09:07 -0800471 struct dirent* dp;
Mark Salyzync18c2132016-04-01 07:52:20 -0700472
Mark Salyzynde022a82017-03-01 08:30:06 -0800473 while (!!(dp = readdir(dir.get()))) {
474 if ((dp->d_type != DT_REG) || !!strncmp(dp->d_name, file, len) ||
Mark Salyzyn5f606602017-02-10 13:09:07 -0800475 (dp->d_name[len] && ((dp->d_name[len] != '.') ||
Mark Salyzynde022a82017-03-01 08:30:06 -0800476 (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) {
Mark Salyzynf3555d92015-05-27 07:39:56 -0700477 continue;
478 }
479
480 std::string file_name = directory;
481 file_name += "/";
482 file_name += dp->d_name;
483 std::string file;
Mark Salyzynde022a82017-03-01 08:30:06 -0800484 if (!android::base::ReadFileToString(file_name, &file)) continue;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700485
486 bool found = false;
487 for (const auto& line : android::base::Split(file, "\n")) {
488 log_time t(log_time::EPOCH);
Mark Salyzyn5f606602017-02-10 13:09:07 -0800489 char* ep = parseTime(t, line.c_str());
Mark Salyzynde022a82017-03-01 08:30:06 -0800490 if (!ep || (*ep != ' ')) continue;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700491 // determine the time precision of the logs (eg: msec or usec)
492 for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
493 if (t.tv_nsec % (mod * 10)) {
494 modulo.tv_nsec = mod;
495 break;
496 }
497 }
498 // We filter any times later than current as we may not have the
499 // year stored with each log entry. Also, since it is possible for
500 // entries to be recorded out of order (very rare) we select the
501 // maximum we find just in case.
502 if ((t < now) && (t > retval)) {
503 retval = t;
504 found = true;
505 }
506 }
507 // We count on the basename file to be the definitive end, so stop here.
Mark Salyzynde022a82017-03-01 08:30:06 -0800508 if (!dp->d_name[len] && found) break;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700509 }
Mark Salyzynde022a82017-03-01 08:30:06 -0800510 if (retval == log_time::EPOCH) return retval;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700511 // tail_time prints matching or higher, round up by the modulo to prevent
512 // a replay of the last entry we have just checked.
513 retval += modulo;
514 return retval;
515}
516
Tom Cherry6f061e82019-10-29 07:05:24 -0700517void ReportErrorName(const std::string& name, bool allow_security,
518 std::vector<std::string>* errors) {
519 if (allow_security || name != "security") {
520 errors->emplace_back(name);
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800521 }
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800522}
Traian Schiau59763032015-04-10 15:51:39 +0300523
Tom Cherryd162f142019-10-24 17:35:26 -0700524int Logcat::Run(int argc, char** argv) {
Mark Salyzynb45a1752017-02-28 09:20:31 -0800525 bool hasSetLogFormat = false;
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800526 bool clearLog = false;
Tom Cherry6f061e82019-10-29 07:05:24 -0700527 bool security_buffer_selected =
528 false; // Do not report errors on the security buffer unless it is explicitly named.
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800529 bool getLogSize = false;
530 bool getPruneList = false;
531 bool printStatistics = false;
532 bool printDividers = false;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800533 unsigned long setLogSize = 0;
Mark Salyzyne9ade172017-03-02 15:09:41 -0800534 const char* setPruneList = nullptr;
535 const char* setId = nullptr;
Tom Cherry907b2d02020-03-23 13:40:10 -0700536 int mode = 0;
Mark Salyzynf3290292017-02-10 13:09:07 -0800537 std::string forceFilters;
Traian Schiau59763032015-04-10 15:51:39 +0300538 size_t tail_lines = 0;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800539 log_time tail_time(log_time::EPOCH);
Kristian Monsen562e5132015-06-05 14:10:12 -0700540 size_t pid = 0;
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700541 bool got_t = false;
Tom Cherry6f061e82019-10-29 07:05:24 -0700542 unsigned id_mask = 0;
Tom Cherry9291f0f2020-04-13 10:07:53 -0700543 std::set<uid_t> uids;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800544
Mark Salyzynde022a82017-03-01 08:30:06 -0800545 if (argc == 2 && !strcmp(argv[1], "--help")) {
Tom Cherryd162f142019-10-24 17:35:26 -0700546 show_help();
547 return EXIT_SUCCESS;
Mark Salyzync0cf90d2017-02-10 13:09:07 -0800548 }
549
Mark Salyzynb45a1752017-02-28 09:20:31 -0800550 // meant to catch comma-delimited values, but cast a wider
551 // net for stability dealing with possible mistaken inputs.
552 static const char delimiters[] = ",:; \t\n\r\f";
553
Elliott Hughes61b580e2018-06-15 15:16:20 -0700554 optind = 0;
555 while (true) {
Kristian Monsen562e5132015-06-05 14:10:12 -0700556 int option_index = 0;
Mark Salyzync9202772016-03-30 09:38:31 -0700557 // list of long-argument only strings for later comparison
Kristian Monsen562e5132015-06-05 14:10:12 -0700558 static const char pid_str[] = "pid";
Mark Salyzyn538bc122016-11-16 15:28:31 -0800559 static const char debug_str[] = "debug";
Mark Salyzyn02687e72016-08-03 14:20:41 -0700560 static const char id_str[] = "id";
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800561 static const char wrap_str[] = "wrap";
Mark Salyzync9202772016-03-30 09:38:31 -0700562 static const char print_str[] = "print";
Tom Cherry9291f0f2020-04-13 10:07:53 -0700563 static const char uid_str[] = "uid";
Mark Salyzyn5f606602017-02-10 13:09:07 -0800564 // clang-format off
Kristian Monsen562e5132015-06-05 14:10:12 -0700565 static const struct option long_options[] = {
Mark Salyzynde022a82017-03-01 08:30:06 -0800566 { "binary", no_argument, nullptr, 'B' },
567 { "buffer", required_argument, nullptr, 'b' },
568 { "buffer-size", optional_argument, nullptr, 'g' },
569 { "clear", no_argument, nullptr, 'c' },
570 { debug_str, no_argument, nullptr, 0 },
571 { "dividers", no_argument, nullptr, 'D' },
572 { "file", required_argument, nullptr, 'f' },
573 { "format", required_argument, nullptr, 'v' },
Mark Salyzync18c2132016-04-01 07:52:20 -0700574 // hidden and undocumented reserved alias for --regex
Mark Salyzynde022a82017-03-01 08:30:06 -0800575 { "grep", required_argument, nullptr, 'e' },
Mark Salyzynd85f6462016-03-30 09:15:09 -0700576 // hidden and undocumented reserved alias for --max-count
Mark Salyzynde022a82017-03-01 08:30:06 -0800577 { "head", required_argument, nullptr, 'm' },
Mark Salyzyne74e51d2017-04-03 09:30:20 -0700578 { "help", no_argument, nullptr, 'h' },
Mark Salyzynde022a82017-03-01 08:30:06 -0800579 { id_str, required_argument, nullptr, 0 },
580 { "last", no_argument, nullptr, 'L' },
581 { "max-count", required_argument, nullptr, 'm' },
582 { pid_str, required_argument, nullptr, 0 },
583 { print_str, no_argument, nullptr, 0 },
584 { "prune", optional_argument, nullptr, 'p' },
585 { "regex", required_argument, nullptr, 'e' },
586 { "rotate-count", required_argument, nullptr, 'n' },
587 { "rotate-kbytes", required_argument, nullptr, 'r' },
588 { "statistics", no_argument, nullptr, 'S' },
Mark Salyzynd85f6462016-03-30 09:15:09 -0700589 // hidden and undocumented reserved alias for -t
Mark Salyzynde022a82017-03-01 08:30:06 -0800590 { "tail", required_argument, nullptr, 't' },
Tom Cherry9291f0f2020-04-13 10:07:53 -0700591 { uid_str, required_argument, nullptr, 0 },
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800592 // support, but ignore and do not document, the optional argument
Mark Salyzynde022a82017-03-01 08:30:06 -0800593 { wrap_str, optional_argument, nullptr, 0 },
594 { nullptr, 0, nullptr, 0 }
Kristian Monsen562e5132015-06-05 14:10:12 -0700595 };
Mark Salyzyn5f606602017-02-10 13:09:07 -0800596 // clang-format on
Kristian Monsen562e5132015-06-05 14:10:12 -0700597
Elliott Hughes61b580e2018-06-15 15:16:20 -0700598 int c = getopt_long(argc, argv, ":cdDhLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", long_options,
599 &option_index);
600 if (c == -1) break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800601
Elliott Hughes61b580e2018-06-15 15:16:20 -0700602 switch (c) {
Kristian Monsen562e5132015-06-05 14:10:12 -0700603 case 0:
Mark Salyzyn02687e72016-08-03 14:20:41 -0700604 // only long options
Kristian Monsen562e5132015-06-05 14:10:12 -0700605 if (long_options[option_index].name == pid_str) {
Steven Morelandb0e867a2019-08-02 10:13:57 -0700606 if (pid != 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800607 error(EXIT_FAILURE, 0, "Only one --pid argument can be provided.");
Steven Morelandb0e867a2019-08-02 10:13:57 -0700608 }
609
Tom Cherry6f061e82019-10-29 07:05:24 -0700610 if (!ParseUint(optarg, &pid) || pid < 1) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800611 error(EXIT_FAILURE, 0, "%s %s out of range.",
612 long_options[option_index].name, optarg);
Kristian Monsen562e5132015-06-05 14:10:12 -0700613 }
614 break;
615 }
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800616 if (long_options[option_index].name == wrap_str) {
Tom Cherry907b2d02020-03-23 13:40:10 -0700617 mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK;
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800618 // ToDo: implement API that supports setting a wrap timeout
619 size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
Tom Cherry6f061e82019-10-29 07:05:24 -0700620 if (optarg && (!ParseUint(optarg, &dummy) || dummy < 1)) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800621 error(EXIT_FAILURE, 0, "%s %s out of range.",
622 long_options[option_index].name, optarg);
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800623 }
Tom Cherryd162f142019-10-24 17:35:26 -0700624 if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
625 fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
626 long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
627 dummy);
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800628 }
629 break;
630 }
Mark Salyzync9202772016-03-30 09:38:31 -0700631 if (long_options[option_index].name == print_str) {
Tom Cherryd162f142019-10-24 17:35:26 -0700632 print_it_anyways_ = true;
Mark Salyzync9202772016-03-30 09:38:31 -0700633 break;
634 }
Mark Salyzyn538bc122016-11-16 15:28:31 -0800635 if (long_options[option_index].name == debug_str) {
Tom Cherryd162f142019-10-24 17:35:26 -0700636 debug_ = true;
Mark Salyzyn538bc122016-11-16 15:28:31 -0800637 break;
638 }
Mark Salyzyn02687e72016-08-03 14:20:41 -0700639 if (long_options[option_index].name == id_str) {
Elliott Hughes61b580e2018-06-15 15:16:20 -0700640 setId = (optarg && optarg[0]) ? optarg : nullptr;
Mark Salyzyn02687e72016-08-03 14:20:41 -0700641 }
Tom Cherry9291f0f2020-04-13 10:07:53 -0700642 if (long_options[option_index].name == uid_str) {
643 auto uid_strings = Split(optarg, delimiters);
644 for (const auto& uid_string : uid_strings) {
645 uid_t uid;
646 if (!ParseUint(uid_string, &uid)) {
647 error(EXIT_FAILURE, 0, "Unable to parse UID '%s'", uid_string.c_str());
648 }
649 uids.emplace(uid);
650 }
651 break;
652 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800653 break;
Kristian Monsen562e5132015-06-05 14:10:12 -0700654
Mark Salyzyn95132e92013-11-22 10:55:48 -0800655 case 's':
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800656 // default to all silent
Tom Cherryd162f142019-10-24 17:35:26 -0700657 android_log_addFilterRule(logformat_.get(), "*:s");
Mark Salyzyn5f606602017-02-10 13:09:07 -0800658 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800659
660 case 'c':
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800661 clearLog = true;
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':
Tom Cherry907b2d02020-03-23 13:40:10 -0700665 mode |= ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800666 break;
Mark Salyzyn7c975ac2014-12-15 10:01:31 -0800667
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800668 case 'd':
Tom Cherry907b2d02020-03-23 13:40:10 -0700669 mode |= ANDROID_LOG_NONBLOCK;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800670 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800671
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800672 case 't':
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700673 got_t = true;
Tom Cherry907b2d02020-03-23 13:40:10 -0700674 mode |= ANDROID_LOG_NONBLOCK;
Chih-Hung Hsieh502f4862018-09-13 11:08:41 -0700675 FALLTHROUGH_INTENDED;
Mark Salyzyn5d3d1f12013-12-09 13:47:00 -0800676 case 'T':
Elliott Hughes61b580e2018-06-15 15:16:20 -0700677 if (strspn(optarg, "0123456789") != strlen(optarg)) {
678 char* cp = parseTime(tail_time, optarg);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800679 if (!cp) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800680 error(EXIT_FAILURE, 0, "-%c '%s' not in time format.", c, optarg);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800681 }
682 if (*cp) {
Elliott Hughes61b580e2018-06-15 15:16:20 -0700683 char ch = *cp;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800684 *cp = '\0';
Tom Cherry72a4e082019-12-06 10:25:37 -0800685 fprintf(stderr, "WARNING: -%c '%s' '%c%s' time truncated\n", c, optarg, ch,
686 cp + 1);
Elliott Hughes61b580e2018-06-15 15:16:20 -0700687 *cp = ch;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800688 }
689 } else {
Tom Cherry6f061e82019-10-29 07:05:24 -0700690 if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
Tom Cherryd162f142019-10-24 17:35:26 -0700691 fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800692 tail_lines = 1;
693 }
694 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800695 break;
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800696
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800697 case 'D':
698 printDividers = true;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800699 break;
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800700
Casey Dahlindc42a872016-03-17 16:18:55 -0700701 case 'e':
Tom Cherryd162f142019-10-24 17:35:26 -0700702 regex_.reset(new std::regex(optarg));
Mark Salyzyn5f606602017-02-10 13:09:07 -0800703 break;
Casey Dahlindc42a872016-03-17 16:18:55 -0700704
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700705 case 'm': {
Tom Cherry6f061e82019-10-29 07:05:24 -0700706 if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800707 error(EXIT_FAILURE, 0, "-%c '%s' isn't an integer greater than zero.", c,
708 optarg);
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700709 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800710 } break;
Casey Dahlin6ac498d2016-03-17 14:04:52 -0700711
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800712 case 'g':
Elliott Hughes61b580e2018-06-15 15:16:20 -0700713 if (!optarg) {
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800714 getLogSize = true;
Mark Salyzynf8bff872015-11-30 12:57:56 -0800715 break;
716 }
Chih-Hung Hsieh502f4862018-09-13 11:08:41 -0700717 FALLTHROUGH_INTENDED;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800718
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800719 case 'G': {
Tom Cherry6f061e82019-10-29 07:05:24 -0700720 if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800721 error(EXIT_FAILURE, 0, "-G must be specified as <num><multiplier>.");
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800722 }
Mark Salyzyn5f606602017-02-10 13:09:07 -0800723 } break;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800724
725 case 'p':
Elliott Hughes61b580e2018-06-15 15:16:20 -0700726 if (!optarg) {
Mark Salyzyn26a1fac2017-01-20 14:07:29 -0800727 getPruneList = true;
Mark Salyzynf8bff872015-11-30 12:57:56 -0800728 break;
729 }
Chih-Hung Hsieh502f4862018-09-13 11:08:41 -0700730 FALLTHROUGH_INTENDED;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800731
732 case 'P':
Elliott Hughes61b580e2018-06-15 15:16:20 -0700733 setPruneList = optarg;
Mark Salyzyn5f606602017-02-10 13:09:07 -0800734 break;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800735
Tom Cherry6f061e82019-10-29 07:05:24 -0700736 case 'b':
737 for (const auto& buffer : Split(optarg, delimiters)) {
738 if (buffer == "default") {
739 id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
740 } else if (buffer == "all") {
741 id_mask = -1;
Mark Salyzyn45177732016-04-11 14:03:48 -0700742 } else {
Tom Cherry6f061e82019-10-29 07:05:24 -0700743 log_id_t log_id = android_name_to_log_id(buffer.c_str());
744 if (log_id >= LOG_ID_MAX) {
Tom Cherry72a4e082019-12-06 10:25:37 -0800745 error(EXIT_FAILURE, 0, "Unknown buffer '%s' listed for -b.",
746 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 Cherry72a4e082019-12-06 10:25:37 -0800770 error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -r.", 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 Cherry72a4e082019-12-06 10:25:37 -0800776 error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -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 Cherry72a4e082019-12-06 10:25:37 -0800788 error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -v.", 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 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);
Joe Onorato6fa09a02010-02-26 10:04:23 -08001067
Tom Cherry6f061e82019-10-29 07:05:24 -07001068 if (size < 0 || readable < 0) {
1069 ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001070 } else {
Wei Wangc27d4812018-09-05 11:05:57 -07001071 auto size_format = format_of_size(size);
1072 auto readable_format = format_of_size(readable);
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001073 std::string str = android::base::StringPrintf(
Tom Cherry6f061e82019-10-29 07:05:24 -07001074 "%s: ring buffer is %lu %sB (%lu %sB consumed),"
1075 " max entry is %d B, max payload is %d B\n",
1076 buffer_name, size_format.first, size_format.second, readable_format.first,
1077 readable_format.second, (int)LOGGER_ENTRY_MAX_LEN,
1078 (int)LOGGER_ENTRY_MAX_PAYLOAD);
Tom Cherryd162f142019-10-24 17:35:26 -07001079 TEMP_FAILURE_RETRY(write(output_fd_.get(), str.data(), str.length()));
Joe Onorato6fa09a02010-02-26 10:04:23 -08001080 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001081 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001082 }
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001083
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001084 // report any errors in the above loop and exit
Tom Cherry6f061e82019-10-29 07:05:24 -07001085 if (!open_device_failures.empty()) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001086 error(EXIT_FAILURE, 0, "Unable to open log device%s '%s'.",
1087 open_device_failures.size() > 1 ? "s" : "", Join(open_device_failures, ",").c_str());
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001088 }
Tom Cherry6f061e82019-10-29 07:05:24 -07001089 if (!clear_failures.empty()) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001090 error(EXIT_FAILURE, 0, "failed to clear the '%s' log%s.", Join(clear_failures, ",").c_str(),
1091 clear_failures.size() > 1 ? "s" : "");
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001092 }
Tom Cherry6f061e82019-10-29 07:05:24 -07001093 if (!set_size_failures.empty()) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001094 error(EXIT_FAILURE, 0, "failed to set the '%s' log size%s.",
1095 Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001096 }
Tom Cherry6f061e82019-10-29 07:05:24 -07001097 if (!get_size_failures.empty()) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001098 error(EXIT_FAILURE, 0, "failed to get the readable '%s' log size%s.",
1099 Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001100 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001101
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001102 if (setPruneList) {
Traian Schiau59763032015-04-10 15:51:39 +03001103 size_t len = strlen(setPruneList);
Tom Cherryed860ff2019-12-06 11:01:51 -08001104 if (android_logger_set_prune_list(logger_list.get(), setPruneList, len)) {
1105 error(EXIT_FAILURE, 0, "Failed to set the prune list.");
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001106 }
Tom Cherryd162f142019-10-24 17:35:26 -07001107 return EXIT_SUCCESS;
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001108 }
1109
Mark Salyzyn1c950472014-04-01 17:19:47 -07001110 if (printStatistics || getPruneList) {
Tom Cherrye17b4f62019-12-06 13:33:11 -08001111 std::string buf(8192, '\0');
1112 size_t ret_length = 0;
1113 int retry = 32;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001114
Tom Cherrye17b4f62019-12-06 13:33:11 -08001115 for (; retry >= 0; --retry) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001116 if (getPruneList) {
Tom Cherrye17b4f62019-12-06 13:33:11 -08001117 android_logger_get_prune_list(logger_list.get(), buf.data(), buf.size());
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001118 } else {
Tom Cherrye17b4f62019-12-06 13:33:11 -08001119 android_logger_get_statistics(logger_list.get(), buf.data(), buf.size());
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001120 }
Tom Cherrye17b4f62019-12-06 13:33:11 -08001121
1122 ret_length = atol(buf.c_str());
1123 if (ret_length < 3) {
1124 error(EXIT_FAILURE, 0, "Failed to read data.");
1125 }
1126
1127 if (ret_length < buf.size()) {
Mark Salyzyn34facab2014-02-06 14:48:50 -08001128 break;
1129 }
Tom Cherrye17b4f62019-12-06 13:33:11 -08001130
1131 buf.resize(ret_length + 1);
Mark Salyzyn34facab2014-02-06 14:48:50 -08001132 }
1133
Tom Cherrye17b4f62019-12-06 13:33:11 -08001134 if (retry < 0) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001135 error(EXIT_FAILURE, 0, "Failed to read data.");
Mark Salyzyn34facab2014-02-06 14:48:50 -08001136 }
1137
Tom Cherrye17b4f62019-12-06 13:33:11 -08001138 buf.resize(ret_length);
1139 if (buf.back() == '\f') {
1140 buf.pop_back();
Mark Salyzyn34facab2014-02-06 14:48:50 -08001141 }
1142
Tom Cherrye17b4f62019-12-06 13:33:11 -08001143 // Remove the byte count prefix
1144 const char* cp = buf.c_str();
1145 while (isdigit(*cp)) ++cp;
1146 if (*cp == '\n') ++cp;
1147
1148 size_t len = strlen(cp);
Tom Cherryd162f142019-10-24 17:35:26 -07001149 TEMP_FAILURE_RETRY(write(output_fd_.get(), cp, len));
Tom Cherryd162f142019-10-24 17:35:26 -07001150 return EXIT_SUCCESS;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001151 }
1152
Tom Cherryd162f142019-10-24 17:35:26 -07001153 if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001154
Tom Cherryd162f142019-10-24 17:35:26 -07001155 SetupOutputAndSchedulingPolicy(!(mode & ANDROID_LOG_NONBLOCK));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001156
Tom Cherryd162f142019-10-24 17:35:26 -07001157 while (!max_count_ || print_count_ < max_count_) {
Mark Salyzyn95132e92013-11-22 10:55:48 -08001158 struct log_msg log_msg;
Tom Cherry6f061e82019-10-29 07:05:24 -07001159 int ret = android_logger_list_read(logger_list.get(), &log_msg);
Mark Salyzynde022a82017-03-01 08:30:06 -08001160 if (!ret) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001161 error(EXIT_FAILURE, 0, R"init(Unexpected EOF!
Tom Cherry41697322019-11-21 10:31:06 -08001162
Tom Cherry26d712e2020-02-14 10:01:57 -08001163This 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 -08001164messages as quickly as they were being produced.
1165
Tom Cherry72a4e082019-12-06 10:25:37 -08001166If you have enabled significant logging, look into using the -G option to increase log buffer sizes.)init");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001167 }
1168
1169 if (ret < 0) {
Mark Salyzynde022a82017-03-01 08:30:06 -08001170 if (ret == -EAGAIN) break;
Mark Salyzyn95132e92013-11-22 10:55:48 -08001171
1172 if (ret == -EIO) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001173 error(EXIT_FAILURE, 0, "Unexpected EOF!");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001174 }
1175 if (ret == -EINVAL) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001176 error(EXIT_FAILURE, 0, "Unexpected length.");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001177 }
Tom Cherry72a4e082019-12-06 10:25:37 -08001178 error(EXIT_FAILURE, errno, "Logcat read failure");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001179 }
1180
Tom Cherry6f061e82019-10-29 07:05:24 -07001181 if (log_msg.id() > LOG_ID_MAX) {
Tom Cherry72a4e082019-12-06 10:25:37 -08001182 error(EXIT_FAILURE, 0, "Unexpected log id (%d) over LOG_ID_MAX (%d).", log_msg.id(),
1183 LOG_ID_MAX);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001184 }
1185
Tom Cherry9291f0f2020-04-13 10:07:53 -07001186 if (!uids.empty() && uids.count(log_msg.entry.uid) == 0) {
1187 continue;
1188 }
1189
Tom Cherry6f061e82019-10-29 07:05:24 -07001190 PrintDividers(log_msg.id(), printDividers);
1191
Tom Cherryd162f142019-10-24 17:35:26 -07001192 if (print_binary_) {
1193 TEMP_FAILURE_RETRY(write(output_fd_.get(), &log_msg, log_msg.len()));
Mark Salyzyn95132e92013-11-22 10:55:48 -08001194 } else {
Tom Cherry6f061e82019-10-29 07:05:24 -07001195 ProcessBuffer(&log_msg);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001196 }
1197 }
Tom Cherryd162f142019-10-24 17:35:26 -07001198 return EXIT_SUCCESS;
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001199}
1200
Tom Cherry98c6c332019-10-30 13:51:03 -07001201int main(int argc, char** argv) {
Tom Cherryd162f142019-10-24 17:35:26 -07001202 Logcat logcat;
1203 return logcat.Run(argc, argv);
Mark Salyzync0cf90d2017-02-10 13:09:07 -08001204}