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