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