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