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