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