blob: 87524b43738a3a32f57ba79687756111b88dc37f [file] [log] [blame]
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001// Copyright 2006-2015 The Android Open Source Project
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08002
Mark Salyzyn3ef730c2015-06-02 07:57:16 -07003#include <arpa/inet.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -08004#include <assert.h>
5#include <ctype.h>
Mark Salyzynf3555d92015-05-27 07:39:56 -07006#include <dirent.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -08007#include <errno.h>
8#include <fcntl.h>
Kristian Monsen562e5132015-06-05 14:10:12 -07009#include <getopt.h>
Aristidis Papaioannoueba73442014-10-16 22:19:55 -070010#include <math.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070011#include <sched.h>
12#include <signal.h>
13#include <stdarg.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080014#include <stdio.h>
15#include <stdlib.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080016#include <string.h>
Traian Schiau59763032015-04-10 15:51:39 +030017#include <sys/cdefs.h>
Riley Andrewsaede9892015-06-08 23:36:34 -070018#include <sys/resource.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080019#include <sys/socket.h>
20#include <sys/stat.h>
Mark Salyzynf3555d92015-05-27 07:39:56 -070021#include <sys/types.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070022#include <time.h>
23#include <unistd.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080024
Mark Salyzynf3555d92015-05-27 07:39:56 -070025#include <memory>
26#include <string>
27
Elliott Hughes4f713192015-12-04 22:00:26 -080028#include <android-base/file.h>
29#include <android-base/strings.h>
padarshr0040c332016-07-22 17:12:16 +053030#include <cutils/properties.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070031#include <cutils/sched_policy.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080032#include <cutils/sockets.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070033#include <log/event_tag_map.h>
Mark Salyzyn95132e92013-11-22 10:55:48 -080034#include <log/log.h>
Mark Salyzynfa3716b2014-02-14 16:05:05 -080035#include <log/log_read.h>
Colin Cross9227bd32013-07-23 16:59:20 -070036#include <log/logd.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070037#include <log/logger.h>
Colin Cross9227bd32013-07-23 16:59:20 -070038#include <log/logprint.h>
Riley Andrewsaede9892015-06-08 23:36:34 -070039#include <utils/threads.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080040
Casey Dahlin0f7732d2016-03-17 16:18:55 -070041#include <pcrecpp.h>
42
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080043#define DEFAULT_MAX_ROTATED_LOGS 4
44
45static AndroidLogFormat * g_logformat;
46
47/* logd prefixes records with a length field */
48#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
49
Joe Onorato6fa09a02010-02-26 10:04:23 -080050struct log_device_t {
Mark Salyzyn95132e92013-11-22 10:55:48 -080051 const char* device;
Joe Onorato6fa09a02010-02-26 10:04:23 -080052 bool binary;
Mark Salyzyn95132e92013-11-22 10:55:48 -080053 struct logger *logger;
54 struct logger_list *logger_list;
Joe Onorato6fa09a02010-02-26 10:04:23 -080055 bool printed;
Joe Onorato6fa09a02010-02-26 10:04:23 -080056
Joe Onorato6fa09a02010-02-26 10:04:23 -080057 log_device_t* next;
58
Mark Salyzyn5f6738a2015-02-27 13:41:34 -080059 log_device_t(const char* d, bool b) {
Joe Onorato6fa09a02010-02-26 10:04:23 -080060 device = d;
61 binary = b;
Joe Onorato6fa09a02010-02-26 10:04:23 -080062 next = NULL;
63 printed = false;
Traian Schiau59763032015-04-10 15:51:39 +030064 logger = NULL;
65 logger_list = NULL;
Joe Onorato6fa09a02010-02-26 10:04:23 -080066 }
Joe Onorato6fa09a02010-02-26 10:04:23 -080067};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080068
69namespace android {
70
71/* Global Variables */
72
Mark Salyzyn9cc9cf02016-03-30 12:38:29 -070073static const char * g_outputFileName;
padarshr0040c332016-07-22 17:12:16 +053074static const char * g_outputPartitionName = NULL;
Traian Schiau59763032015-04-10 15:51:39 +030075// 0 means "no log rotation"
Mark Salyzyn9cc9cf02016-03-30 12:38:29 -070076static size_t g_logRotateSizeKBytes;
Traian Schiau59763032015-04-10 15:51:39 +030077// 0 means "unbounded"
78static size_t g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080079static int g_outFD = -1;
padarshr0040c332016-07-22 17:12:16 +053080static int g_logDumpFD = -1;
Mark Salyzyn9cc9cf02016-03-30 12:38:29 -070081static size_t g_outByteCount;
padarshr0040c332016-07-22 17:12:16 +053082static size_t g_outByteCountOfLogDump;
Mark Salyzyn9cc9cf02016-03-30 12:38:29 -070083static int g_printBinary;
84static int g_devCount; // >1 means multiple
Casey Dahlin0f7732d2016-03-17 16:18:55 -070085static pcrecpp::RE* g_regex;
Casey Dahlin1164ef62016-03-17 14:04:52 -070086// 0 means "infinite"
Mark Salyzyn9cc9cf02016-03-30 12:38:29 -070087static size_t g_maxCount;
88static size_t g_printCount;
Mark Salyzyn3bef8972016-03-30 09:38:31 -070089static bool g_printItAnyways;
padarshr0040c332016-07-22 17:12:16 +053090static bool g_logDumpEnabled;
91static size_t g_logDumpEndPosition = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080092
Mark Salyzyndf42ce42016-03-30 12:38:29 -070093// if showHelp is set, newline required in fmt statement to transition to usage
Traian Schiau59763032015-04-10 15:51:39 +030094__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
95
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080096static int openLogFile (const char *pathname)
97{
Edwin Vane80b221c2012-08-13 12:55:07 -040098 return open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080099}
100
101static void rotateLogs()
102{
103 int err;
104
105 // Can't rotate logs if we're not outputting to a file
106 if (g_outputFileName == NULL) {
107 return;
108 }
109
110 close(g_outFD);
111
Aristidis Papaioannoueba73442014-10-16 22:19:55 -0700112 // Compute the maximum number of digits needed to count up to g_maxRotatedLogs in decimal.
113 // eg: g_maxRotatedLogs == 30 -> log10(30) == 1.477 -> maxRotationCountDigits == 2
114 int maxRotationCountDigits =
115 (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
116
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800117 for (int i = g_maxRotatedLogs ; i > 0 ; i--) {
118 char *file0, *file1;
119
Aristidis Papaioannoueba73442014-10-16 22:19:55 -0700120 asprintf(&file1, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800121
122 if (i - 1 == 0) {
123 asprintf(&file0, "%s", g_outputFileName);
124 } else {
Aristidis Papaioannoueba73442014-10-16 22:19:55 -0700125 asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800126 }
127
Traian Schiau59763032015-04-10 15:51:39 +0300128 if (!file0 || !file1) {
129 perror("while rotating log files");
130 break;
131 }
132
133 err = rename(file0, file1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800134
135 if (err < 0 && errno != ENOENT) {
136 perror("while rotating log files");
137 }
138
139 free(file1);
140 free(file0);
141 }
142
Traian Schiau59763032015-04-10 15:51:39 +0300143 g_outFD = openLogFile(g_outputFileName);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800144
145 if (g_outFD < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300146 logcat_panic(false, "couldn't open output file");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800147 }
148
149 g_outByteCount = 0;
150
151}
152
Mark Salyzyn95132e92013-11-22 10:55:48 -0800153void printBinary(struct log_msg *buf)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800154{
Mark Salyzyn95132e92013-11-22 10:55:48 -0800155 size_t size = buf->len();
156
157 TEMP_FAILURE_RETRY(write(g_outFD, buf, size));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800158}
159
padarshr0040c332016-07-22 17:12:16 +0530160static void checkAndRotateLogDump(size_t logLength)
161{
162 if (g_outByteCountOfLogDump + logLength >= g_logDumpEndPosition) {
163 lseek(g_logDumpFD, 0, SEEK_SET);
164 g_outByteCountOfLogDump = 0;
165 }
166}
167
168static void writeEntryToLogDump(AndroidLogEntry *entry)
169{
170 int bytesWrittenToLogDump = 0;
171 char defaultBuffer[512];
padarshr17afa902016-09-28 17:55:42 +0530172 char *outBuffer = NULL;
padarshr0040c332016-07-22 17:12:16 +0530173 size_t logLength;
174
175 // Get logLength
padarshr17afa902016-09-28 17:55:42 +0530176 outBuffer = android_log_formatLogLine(g_logformat, defaultBuffer,
177 sizeof(defaultBuffer),
178 entry,
179 &logLength);
180 if (outBuffer != defaultBuffer) {
181 free(outBuffer);
182 }
padarshr0040c332016-07-22 17:12:16 +0530183
184 // Check if the to-be-inserted log exceeds the available buffer size; And rotate if needed.
185 checkAndRotateLogDump(logLength);
186
187 bytesWrittenToLogDump = android_log_printLogLine(g_logformat, g_logDumpFD, entry);
188
189 if (bytesWrittenToLogDump < 0) {
190 logcat_panic(false, "output error");
191 }
192
193 g_outByteCountOfLogDump += bytesWrittenToLogDump;
194}
195
Mark Salyzyndf42ce42016-03-30 12:38:29 -0700196static bool regexOk(const AndroidLogEntry& entry)
Casey Dahlin0f7732d2016-03-17 16:18:55 -0700197{
Mark Salyzyndf42ce42016-03-30 12:38:29 -0700198 if (!g_regex) {
Casey Dahlin0f7732d2016-03-17 16:18:55 -0700199 return true;
200 }
201
Casey Dahlin0f7732d2016-03-17 16:18:55 -0700202 std::string messageString(entry.message, entry.messageLen);
203
204 return g_regex->PartialMatch(messageString);
205}
206
Mark Salyzyn95132e92013-11-22 10:55:48 -0800207static void processBuffer(log_device_t* dev, struct log_msg *buf)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800208{
Mathias Agopian50844522010-03-17 16:10:26 -0700209 int bytesWritten = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800210 int err;
211 AndroidLogEntry entry;
212 char binaryMsgBuf[1024];
213
Joe Onorato6fa09a02010-02-26 10:04:23 -0800214 if (dev->binary) {
Mark Salyzyn9421b0c2015-02-26 14:33:35 -0800215 static bool hasOpenedEventTagMap = false;
216 static EventTagMap *eventTagMap = NULL;
217
218 if (!eventTagMap && !hasOpenedEventTagMap) {
219 eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
220 hasOpenedEventTagMap = true;
221 }
Mark Salyzyn95132e92013-11-22 10:55:48 -0800222 err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
Mark Salyzyn9421b0c2015-02-26 14:33:35 -0800223 eventTagMap,
Mark Salyzyn95132e92013-11-22 10:55:48 -0800224 binaryMsgBuf,
225 sizeof(binaryMsgBuf));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800226 //printf(">>> pri=%d len=%d msg='%s'\n",
227 // entry.priority, entry.messageLen, entry.message);
228 } else {
Mark Salyzyn95132e92013-11-22 10:55:48 -0800229 err = android_log_processLogBuffer(&buf->entry_v1, &entry);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800230 }
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800231 if (err < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800232 goto error;
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800233 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800234
Mark Salyzyn3bef8972016-03-30 09:38:31 -0700235 if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
padarshr0040c332016-07-22 17:12:16 +0530236 if (g_logDumpEnabled) {
237 writeEntryToLogDump(&entry);
238 }
239
Mark Salyzyn3bef8972016-03-30 09:38:31 -0700240 bool match = regexOk(entry);
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800241
Mark Salyzyn3bef8972016-03-30 09:38:31 -0700242 g_printCount += match;
243 if (match || g_printItAnyways) {
244 bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
Casey Dahlin1164ef62016-03-17 14:04:52 -0700245
Mark Salyzyn3bef8972016-03-30 09:38:31 -0700246 if (bytesWritten < 0) {
247 logcat_panic(false, "output error");
248 }
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800249 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800250 }
251
252 g_outByteCount += bytesWritten;
253
Mark Salyzyn95132e92013-11-22 10:55:48 -0800254 if (g_logRotateSizeKBytes > 0
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800255 && (g_outByteCount / 1024) >= g_logRotateSizeKBytes
256 ) {
257 rotateLogs();
258 }
259
260error:
261 //fprintf (stderr, "Error processing record\n");
262 return;
263}
264
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800265static void maybePrintStart(log_device_t* dev, bool printDividers) {
266 if (!dev->printed || printDividers) {
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800267 if (g_devCount > 1 && !g_printBinary) {
268 char buf[1024];
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800269 snprintf(buf, sizeof(buf), "--------- %s %s\n",
270 dev->printed ? "switch to" : "beginning of",
Mark Salyzyn95132e92013-11-22 10:55:48 -0800271 dev->device);
padarshr0040c332016-07-22 17:12:16 +0530272 if (g_logDumpEnabled) {
273 checkAndRotateLogDump(strlen(buf));
274 int bytesWrittenToLogDump = write(g_logDumpFD, buf, strlen(buf));
275 if (bytesWrittenToLogDump < 0) {
276 logcat_panic(false, "output error");
277 }
278 g_outByteCountOfLogDump += bytesWrittenToLogDump;
279 }
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800280 if (write(g_outFD, buf, strlen(buf)) < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300281 logcat_panic(false, "output error");
Joe Onorato6fa09a02010-02-26 10:04:23 -0800282 }
283 }
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800284 dev->printed = true;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800285 }
286}
287
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800288static void setupOutput()
289{
padarshr0040c332016-07-22 17:12:16 +0530290 if (g_logDumpEnabled) {
291 if (g_outputPartitionName == NULL) {
292 property_set("ctl.stop","logdumpd");
293 logcat_panic(false, "partition name is null");
294 }
295
296 struct stat statbuf;
297 if (stat(g_outputPartitionName, &statbuf) == -1) {
298 property_set("ctl.stop","logdumpd");
299 logcat_panic(false, "Couldn't stat output partition\n");
300 }
301
302 g_logDumpFD = openLogFile (g_outputPartitionName);
303 if (g_logDumpFD < 0) {
304 property_set("ctl.stop","logdumpd");
305 logcat_panic(false, "Can't open output partition");
306 }
307
308 //save end of partition to be used later for log rotation
309 g_logDumpEndPosition = lseek(g_logDumpFD, 0, SEEK_END);
310 //set back file offset to the beginning
311 lseek(g_logDumpFD, 0, SEEK_SET);
312 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800313
314 if (g_outputFileName == NULL) {
315 g_outFD = STDOUT_FILENO;
316
317 } else {
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700318 if (set_sched_policy(0, SP_BACKGROUND) < 0) {
319 fprintf(stderr, "failed to set background scheduling policy\n");
320 }
321
322 struct sched_param param;
323 memset(&param, 0, sizeof(param));
324 if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
325 fprintf(stderr, "failed to set to batch scheduler\n");
326 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800327
Riley Andrewsaede9892015-06-08 23:36:34 -0700328 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
329 fprintf(stderr, "failed set to priority\n");
330 }
331
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800332 g_outFD = openLogFile (g_outputFileName);
333
334 if (g_outFD < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300335 logcat_panic(false, "couldn't open output file");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800336 }
337
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700338 struct stat statbuf;
Traian Schiau59763032015-04-10 15:51:39 +0300339 if (fstat(g_outFD, &statbuf) == -1) {
340 close(g_outFD);
341 logcat_panic(false, "couldn't get output file stat\n");
342 }
343
344 if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
345 close(g_outFD);
346 logcat_panic(false, "invalid output file stat\n");
347 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800348
349 g_outByteCount = statbuf.st_size;
350 }
351}
352
353static void show_help(const char *cmd)
354{
355 fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
356
357 fprintf(stderr, "options include:\n"
Mark Salyzyn3f6777a2016-04-12 09:11:46 -0700358 " -s Set default filter to silent. Equivalent to filterspec '*:S'\n"
359 " -f <file>, --file=<file> Log to file. Default is stdout\n"
360 " -r <kbytes>, --rotate-kbytes=<kbytes>\n"
361 " Rotate log every kbytes. Requires -f option\n"
362 " -n <count>, --rotate-count=<count>\n"
363 " Sets max number of rotated logs to <count>, default 4\n"
364 " -v <format>, --format=<format>\n"
365 " Sets the log print format, where <format> is:\n"
366 " brief color epoch long monotonic printable process raw\n"
367 " tag thread threadtime time uid usec UTC year zone\n"
368 " -D, --dividers Print dividers between each log buffer\n"
369 " -c, --clear Clear (flush) the entire log and exit\n"
Mark Salyzync8699592016-06-06 14:56:00 -0700370 " if Log to File specified, clear fileset instead\n"
Mark Salyzyn3f6777a2016-04-12 09:11:46 -0700371 " -d Dump the log and then exit (don't block)\n"
372 " -e <expr>, --regex=<expr>\n"
373 " Only print lines where the log message matches <expr>\n"
374 " where <expr> is a regular expression\n"
375 // Leave --head undocumented as alias for -m
376 " -m <count>, --max-count=<count>\n"
377 " Quit after printing <count> lines. This is meant to be\n"
378 " paired with --regex, but will work on its own.\n"
379 " --print Paired with --regex and --max-count to let content bypass\n"
Mark Salyzyn3bef8972016-03-30 09:38:31 -0700380 " regex filter but still stop at number of matches.\n"
Mark Salyzyn3f6777a2016-04-12 09:11:46 -0700381 // Leave --tail undocumented as alias for -t
382 " -t <count> Print only the most recent <count> lines (implies -d)\n"
383 " -t '<time>' Print most recent lines since specified time (implies -d)\n"
384 " -T <count> Print only the most recent <count> lines (does not imply -d)\n"
385 " -T '<time>' Print most recent lines since specified time (not imply -d)\n"
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700386 " count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'\n"
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700387 " 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format\n"
Mark Salyzyn3f6777a2016-04-12 09:11:46 -0700388 " -g, --buffer-size Get the size of the ring buffer.\n"
389 " -G <size>, --buffer-size=<size>\n"
390 " Set size of log ring buffer, may suffix with K or M.\n"
391 " -L, -last Dump logs from prior to last reboot\n"
Mark Salyzyn083b0372015-12-04 10:59:45 -0800392 // Leave security (Device Owner only installations) and
393 // kernel (userdebug and eng) buffers undocumented.
Mark Salyzyn3f6777a2016-04-12 09:11:46 -0700394 " -b <buffer>, --buffer=<buffer> Request alternate ring buffer, 'main',\n"
395 " 'system', 'radio', 'events', 'crash', 'default' or 'all'.\n"
Mark Salyzyn7545b472016-04-11 14:03:48 -0700396 " Multiple -b parameters or comma separated list of buffers are\n"
397 " allowed. Buffers interleaved. Default -b main,system,crash.\n"
Mark Salyzyn3f6777a2016-04-12 09:11:46 -0700398 " -B, --binary Output the log in binary.\n"
399 " -S, --statistics Output statistics.\n"
400 " -p, --prune Print prune white and ~black list. Service is specified as\n"
401 " UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
Mark Salyzynbbbe14f2014-04-11 13:49:43 -0700402 " with ~, otherwise weighed for longevity if unadorned. All\n"
403 " other pruning activity is oldest first. Special case ~!\n"
404 " represents an automatic quicker pruning for the noisiest\n"
405 " UID as determined by the current statistics.\n"
Mark Salyzyn3f6777a2016-04-12 09:11:46 -0700406 " -P '<list> ...', --prune='<list> ...'\n"
407 " Set prune white and ~black list, using same format as\n"
408 " listed above. Must be quoted.\n"
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800409 " --pid=<pid> Only prints logs from the given pid.\n"
Mark Salyzyn3f6777a2016-04-12 09:11:46 -0700410 // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value for match to 2 hours
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800411 " --wrap Sleep for 2 hours or when buffer about to wrap whichever\n"
412 " comes first. Improves efficiency of polling by providing\n"
413 " an about-to-wrap wakeup.\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800414
415 fprintf(stderr,"\nfilterspecs are a series of \n"
416 " <tag>[:priority]\n\n"
417 "where <tag> is a log component tag (or * for all) and priority is:\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700418 " V Verbose (default for <tag>)\n"
419 " D Debug (default for '*')\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800420 " I Info\n"
421 " W Warn\n"
422 " E Error\n"
423 " F Fatal\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700424 " S Silent (suppress all output)\n"
425 "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
426 "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
427 "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
428 "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
429 "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
Mark Salyzyn649fc602014-09-16 09:15:15 -0700430 "or defaults to \"threadtime\"\n\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800431}
432
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800433static int setLogFormat(const char * formatString)
434{
435 static AndroidLogPrintFormat format;
436
437 format = android_log_formatFromString(formatString);
438
439 if (format == FORMAT_OFF) {
440 // FORMAT_OFF means invalid string
441 return -1;
442 }
443
Mark Salyzyne1f20042015-05-06 08:40:40 -0700444 return android_log_setPrintFormat(g_logformat, format);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800445}
446
Mark Salyzyn671e3432014-05-06 07:34:59 -0700447static const char multipliers[][2] = {
448 { "" },
449 { "K" },
450 { "M" },
451 { "G" }
452};
453
454static unsigned long value_of_size(unsigned long value)
455{
456 for (unsigned i = 0;
457 (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
458 value /= 1024, ++i) ;
459 return value;
460}
461
462static const char *multiplier_of_size(unsigned long value)
463{
464 unsigned i;
465 for (i = 0;
466 (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
467 value /= 1024, ++i) ;
468 return multipliers[i];
469}
470
Traian Schiau59763032015-04-10 15:51:39 +0300471/*String to unsigned int, returns -1 if it fails*/
472static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0,
473 size_t max = SIZE_MAX)
474{
Kristian Monsen562e5132015-06-05 14:10:12 -0700475 if (!ptr) {
Traian Schiau59763032015-04-10 15:51:39 +0300476 return false;
477 }
478
Kristian Monsen562e5132015-06-05 14:10:12 -0700479 char *endp;
480 errno = 0;
481 size_t ret = (size_t)strtoll(ptr, &endp, 0);
482
483 if (endp[0] || errno) {
484 return false;
485 }
486
487 if ((ret > max) || (ret < min)) {
Traian Schiau59763032015-04-10 15:51:39 +0300488 return false;
489 }
490
491 *val = ret;
492 return true;
493}
494
495static void logcat_panic(bool showHelp, const char *fmt, ...)
496{
Mark Salyzyn77d7e812015-04-13 09:27:57 -0700497 va_list args;
498 va_start(args, fmt);
499 vfprintf(stderr, fmt, args);
500 va_end(args);
Traian Schiau59763032015-04-10 15:51:39 +0300501
502 if (showHelp) {
503 show_help(getprogname());
504 }
505
506 exit(EXIT_FAILURE);
507}
508
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700509static char *parseTime(log_time &t, const char *cp) {
510
511 char *ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
512 if (ep) {
513 return ep;
514 }
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700515 ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
516 if (ep) {
517 return ep;
518 }
519 return t.strptime(cp, "%s.%q");
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700520}
Mark Salyzynf3555d92015-05-27 07:39:56 -0700521
522// Find last logged line in gestalt of all matching existing output files
523static log_time lastLogTime(char *outputFileName) {
524 log_time retval(log_time::EPOCH);
525 if (!outputFileName) {
526 return retval;
527 }
528
Mark Salyzynf3555d92015-05-27 07:39:56 -0700529 std::string directory;
530 char *file = strrchr(outputFileName, '/');
531 if (!file) {
532 directory = ".";
533 file = outputFileName;
534 } else {
535 *file = '\0';
536 directory = outputFileName;
537 *file = '/';
538 ++file;
539 }
Mark Salyzyn1ab87e72016-04-01 07:52:20 -0700540
541 std::unique_ptr<DIR, int(*)(DIR*)>
542 dir(opendir(directory.c_str()), closedir);
543 if (!dir.get()) {
544 return retval;
545 }
546
547 clockid_t clock_type = android_log_clockid();
548 log_time now(clock_type);
549 bool monotonic = clock_type == CLOCK_MONOTONIC;
550
Mark Salyzynf3555d92015-05-27 07:39:56 -0700551 size_t len = strlen(file);
552 log_time modulo(0, NS_PER_SEC);
Mark Salyzynf3555d92015-05-27 07:39:56 -0700553 struct dirent *dp;
Mark Salyzyn1ab87e72016-04-01 07:52:20 -0700554
Mark Salyzynf3555d92015-05-27 07:39:56 -0700555 while ((dp = readdir(dir.get())) != NULL) {
556 if ((dp->d_type != DT_REG)
Mark Salyzynb6bee332015-09-08 08:56:32 -0700557 // If we are using realtime, check all files that match the
558 // basename for latest time. If we are using monotonic time
559 // then only check the main file because time cycles on
560 // every reboot.
561 || strncmp(dp->d_name, file, len + monotonic)
Mark Salyzynf3555d92015-05-27 07:39:56 -0700562 || (dp->d_name[len]
563 && ((dp->d_name[len] != '.')
564 || !isdigit(dp->d_name[len+1])))) {
565 continue;
566 }
567
568 std::string file_name = directory;
569 file_name += "/";
570 file_name += dp->d_name;
571 std::string file;
572 if (!android::base::ReadFileToString(file_name, &file)) {
573 continue;
574 }
575
576 bool found = false;
577 for (const auto& line : android::base::Split(file, "\n")) {
578 log_time t(log_time::EPOCH);
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700579 char *ep = parseTime(t, line.c_str());
Mark Salyzynf3555d92015-05-27 07:39:56 -0700580 if (!ep || (*ep != ' ')) {
581 continue;
582 }
583 // determine the time precision of the logs (eg: msec or usec)
584 for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
585 if (t.tv_nsec % (mod * 10)) {
586 modulo.tv_nsec = mod;
587 break;
588 }
589 }
590 // We filter any times later than current as we may not have the
591 // year stored with each log entry. Also, since it is possible for
592 // entries to be recorded out of order (very rare) we select the
593 // maximum we find just in case.
594 if ((t < now) && (t > retval)) {
595 retval = t;
596 found = true;
597 }
598 }
599 // We count on the basename file to be the definitive end, so stop here.
600 if (!dp->d_name[len] && found) {
601 break;
602 }
603 }
604 if (retval == log_time::EPOCH) {
605 return retval;
606 }
607 // tail_time prints matching or higher, round up by the modulo to prevent
608 // a replay of the last entry we have just checked.
609 retval += modulo;
610 return retval;
611}
612
Traian Schiau59763032015-04-10 15:51:39 +0300613} /* namespace android */
614
615
Joe Onorato6fa09a02010-02-26 10:04:23 -0800616int main(int argc, char **argv)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800617{
Traian Schiau59763032015-04-10 15:51:39 +0300618 using namespace android;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800619 int err;
620 int hasSetLogFormat = 0;
621 int clearLog = 0;
622 int getLogSize = 0;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800623 unsigned long setLogSize = 0;
624 int getPruneList = 0;
625 char *setPruneList = NULL;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800626 int printStatistics = 0;
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800627 int mode = ANDROID_LOG_RDONLY;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800628 const char *forceFilters = NULL;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800629 log_device_t* devices = NULL;
630 log_device_t* dev;
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800631 bool printDividers = false;
Mark Salyzyn95132e92013-11-22 10:55:48 -0800632 struct logger_list *logger_list;
Traian Schiau59763032015-04-10 15:51:39 +0300633 size_t tail_lines = 0;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800634 log_time tail_time(log_time::EPOCH);
Kristian Monsen562e5132015-06-05 14:10:12 -0700635 size_t pid = 0;
Casey Dahlin1164ef62016-03-17 14:04:52 -0700636 bool got_t = false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800637
Mark Salyzyn65772ca2013-12-13 11:10:11 -0800638 signal(SIGPIPE, exit);
639
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800640 g_logformat = android_log_format_new();
641
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800642 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
Traian Schiau59763032015-04-10 15:51:39 +0300643 show_help(argv[0]);
644 return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800645 }
646
647 for (;;) {
648 int ret;
649
Kristian Monsen562e5132015-06-05 14:10:12 -0700650 int option_index = 0;
Mark Salyzyn3bef8972016-03-30 09:38:31 -0700651 // list of long-argument only strings for later comparison
Kristian Monsen562e5132015-06-05 14:10:12 -0700652 static const char pid_str[] = "pid";
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800653 static const char wrap_str[] = "wrap";
Mark Salyzyn3bef8972016-03-30 09:38:31 -0700654 static const char print_str[] = "print";
Kristian Monsen562e5132015-06-05 14:10:12 -0700655 static const struct option long_options[] = {
Mark Salyzynf8bff872015-11-30 12:57:56 -0800656 { "binary", no_argument, NULL, 'B' },
657 { "buffer", required_argument, NULL, 'b' },
Mark Salyzyn7ec59402016-03-30 09:15:09 -0700658 { "buffer-size", optional_argument, NULL, 'g' },
Mark Salyzynf8bff872015-11-30 12:57:56 -0800659 { "clear", no_argument, NULL, 'c' },
660 { "dividers", no_argument, NULL, 'D' },
661 { "file", required_argument, NULL, 'f' },
662 { "format", required_argument, NULL, 'v' },
Mark Salyzyn1ab87e72016-04-01 07:52:20 -0700663 // hidden and undocumented reserved alias for --regex
664 { "grep", required_argument, NULL, 'e' },
Mark Salyzyn7ec59402016-03-30 09:15:09 -0700665 // hidden and undocumented reserved alias for --max-count
666 { "head", required_argument, NULL, 'm' },
Mark Salyzynf8bff872015-11-30 12:57:56 -0800667 { "last", no_argument, NULL, 'L' },
Casey Dahlin1164ef62016-03-17 14:04:52 -0700668 { "max-count", required_argument, NULL, 'm' },
Mark Salyzyn1ab87e72016-04-01 07:52:20 -0700669 { pid_str, required_argument, NULL, 0 },
Mark Salyzyn3bef8972016-03-30 09:38:31 -0700670 { print_str, no_argument, NULL, 0 },
Mark Salyzynf8bff872015-11-30 12:57:56 -0800671 { "prune", optional_argument, NULL, 'p' },
Casey Dahlin0f7732d2016-03-17 16:18:55 -0700672 { "regex", required_argument, NULL, 'e' },
Mark Salyzyn7ec59402016-03-30 09:15:09 -0700673 { "rotate-count", required_argument, NULL, 'n' },
674 { "rotate-kbytes", required_argument, NULL, 'r' },
Mark Salyzynf8bff872015-11-30 12:57:56 -0800675 { "statistics", no_argument, NULL, 'S' },
Mark Salyzyn7ec59402016-03-30 09:15:09 -0700676 // hidden and undocumented reserved alias for -t
677 { "tail", required_argument, NULL, 't' },
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800678 // support, but ignore and do not document, the optional argument
679 { wrap_str, optional_argument, NULL, 0 },
Kristian Monsen562e5132015-06-05 14:10:12 -0700680 { NULL, 0, NULL, 0 }
681 };
682
padarshr0040c332016-07-22 17:12:16 +0530683 ret = getopt_long(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:m:e:w:",
Kristian Monsen562e5132015-06-05 14:10:12 -0700684 long_options, &option_index);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800685
686 if (ret < 0) {
687 break;
688 }
689
Kristian Monsen562e5132015-06-05 14:10:12 -0700690 switch (ret) {
691 case 0:
692 // One of the long options
693 if (long_options[option_index].name == pid_str) {
694 // ToDo: determine runtime PID_MAX?
695 if (!getSizeTArg(optarg, &pid, 1)) {
696 logcat_panic(true, "%s %s out of range\n",
697 long_options[option_index].name, optarg);
698 }
699 break;
700 }
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800701 if (long_options[option_index].name == wrap_str) {
702 mode |= ANDROID_LOG_WRAP |
703 ANDROID_LOG_RDONLY |
704 ANDROID_LOG_NONBLOCK;
705 // ToDo: implement API that supports setting a wrap timeout
706 size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
707 if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
708 logcat_panic(true, "%s %s out of range\n",
709 long_options[option_index].name, optarg);
710 }
711 if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
712 fprintf(stderr,
713 "WARNING: %s %u seconds, ignoring %zu\n",
714 long_options[option_index].name,
715 ANDROID_LOG_WRAP_DEFAULT_TIMEOUT, dummy);
716 }
717 break;
718 }
Mark Salyzyn3bef8972016-03-30 09:38:31 -0700719 if (long_options[option_index].name == print_str) {
720 g_printItAnyways = true;
721 break;
722 }
Kristian Monsen562e5132015-06-05 14:10:12 -0700723 break;
724
Mark Salyzyn95132e92013-11-22 10:55:48 -0800725 case 's':
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800726 // default to all silent
727 android_log_addFilterRule(g_logformat, "*:s");
728 break;
729
730 case 'c':
731 clearLog = 1;
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800732 mode |= ANDROID_LOG_WRONLY;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800733 break;
734
Mark Salyzyn7c975ac2014-12-15 10:01:31 -0800735 case 'L':
736 mode |= ANDROID_LOG_PSTORE;
737 break;
738
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800739 case 'd':
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800740 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800741 break;
742
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800743 case 't':
Casey Dahlin1164ef62016-03-17 14:04:52 -0700744 got_t = true;
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800745 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
Mark Salyzyn5d3d1f12013-12-09 13:47:00 -0800746 /* FALLTHRU */
747 case 'T':
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800748 if (strspn(optarg, "0123456789") != strlen(optarg)) {
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700749 char *cp = parseTime(tail_time, optarg);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800750 if (!cp) {
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700751 logcat_panic(false, "-%c \"%s\" not in time format\n",
752 ret, optarg);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800753 }
754 if (*cp) {
755 char c = *cp;
756 *cp = '\0';
757 fprintf(stderr,
758 "WARNING: -%c \"%s\"\"%c%s\" time truncated\n",
759 ret, optarg, c, cp + 1);
760 *cp = c;
761 }
762 } else {
Traian Schiau59763032015-04-10 15:51:39 +0300763 if (!getSizeTArg(optarg, &tail_lines, 1)) {
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800764 fprintf(stderr,
765 "WARNING: -%c %s invalid, setting to 1\n",
766 ret, optarg);
767 tail_lines = 1;
768 }
769 }
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800770 break;
771
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800772 case 'D':
773 printDividers = true;
774 break;
775
Casey Dahlin0f7732d2016-03-17 16:18:55 -0700776 case 'e':
777 g_regex = new pcrecpp::RE(optarg);
778 break;
779
Casey Dahlin1164ef62016-03-17 14:04:52 -0700780 case 'm': {
781 char *end = NULL;
782 if (!getSizeTArg(optarg, &g_maxCount)) {
783 logcat_panic(false, "-%c \"%s\" isn't an "
784 "integer greater than zero\n", ret, optarg);
785 }
786 }
787 break;
788
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800789 case 'g':
Mark Salyzynf8bff872015-11-30 12:57:56 -0800790 if (!optarg) {
791 getLogSize = 1;
792 break;
793 }
794 // FALLTHRU
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800795
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800796 case 'G': {
Traian Schiau59763032015-04-10 15:51:39 +0300797 char *cp;
798 if (strtoll(optarg, &cp, 0) > 0) {
799 setLogSize = strtoll(optarg, &cp, 0);
800 } else {
801 setLogSize = 0;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800802 }
803
804 switch(*cp) {
805 case 'g':
806 case 'G':
807 setLogSize *= 1024;
808 /* FALLTHRU */
809 case 'm':
810 case 'M':
811 setLogSize *= 1024;
812 /* FALLTHRU */
813 case 'k':
814 case 'K':
815 setLogSize *= 1024;
816 /* FALLTHRU */
817 case '\0':
818 break;
819
820 default:
821 setLogSize = 0;
822 }
823
824 if (!setLogSize) {
825 fprintf(stderr, "ERROR: -G <num><multiplier>\n");
Traian Schiau59763032015-04-10 15:51:39 +0300826 return EXIT_FAILURE;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800827 }
828 }
829 break;
830
831 case 'p':
Mark Salyzynf8bff872015-11-30 12:57:56 -0800832 if (!optarg) {
833 getPruneList = 1;
834 break;
835 }
836 // FALLTHRU
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800837
838 case 'P':
839 setPruneList = optarg;
840 break;
841
Joe Onorato6fa09a02010-02-26 10:04:23 -0800842 case 'b': {
Mark Salyzyn7545b472016-04-11 14:03:48 -0700843 unsigned idMask = 0;
844 while ((optarg = strtok(optarg, ",:; \t\n\r\f")) != NULL) {
845 if (strcmp(optarg, "default") == 0) {
846 idMask |= (1 << LOG_ID_MAIN) |
847 (1 << LOG_ID_SYSTEM) |
848 (1 << LOG_ID_CRASH);
849 } else if (strcmp(optarg, "all") == 0) {
850 idMask = (unsigned)-1;
851 } else {
852 log_id_t log_id = android_name_to_log_id(optarg);
853 const char *name = android_log_id_to_name(log_id);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800854
Mark Salyzyn7545b472016-04-11 14:03:48 -0700855 if (strcmp(name, optarg) != 0) {
856 logcat_panic(true, "unknown buffer %s\n", optarg);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800857 }
Mark Salyzyn7545b472016-04-11 14:03:48 -0700858 idMask |= (1 << log_id);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800859 }
Mark Salyzyn7545b472016-04-11 14:03:48 -0700860 optarg = NULL;
Mark Salyzyn083b0372015-12-04 10:59:45 -0800861 }
862
Mark Salyzyn7545b472016-04-11 14:03:48 -0700863 for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
864 const char *name = android_log_id_to_name((log_id_t)i);
865 log_id_t log_id = android_name_to_log_id(name);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800866
Mark Salyzyn7545b472016-04-11 14:03:48 -0700867 if (log_id != (log_id_t)i) {
868 continue;
869 }
870 if ((idMask & (1 << i)) == 0) {
871 continue;
872 }
Mark Salyzyn083b0372015-12-04 10:59:45 -0800873
Mark Salyzyn7545b472016-04-11 14:03:48 -0700874 bool found = false;
875 for (dev = devices; dev; dev = dev->next) {
876 if (!strcmp(name, dev->device)) {
877 found = true;
Mark Salyzyn083b0372015-12-04 10:59:45 -0800878 break;
879 }
Mark Salyzyn7545b472016-04-11 14:03:48 -0700880 if (!dev->next) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800881 break;
882 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800883 }
Mark Salyzyn7545b472016-04-11 14:03:48 -0700884 if (found) {
885 continue;
886 }
887
888 bool binary = !strcmp(name, "events") ||
889 !strcmp(name, "security");
890 log_device_t* d = new log_device_t(name, binary);
891
Mark Salyzyn083b0372015-12-04 10:59:45 -0800892 if (dev) {
Mark Salyzyn7545b472016-04-11 14:03:48 -0700893 dev->next = d;
894 dev = d;
895 } else {
896 devices = dev = d;
Mark Salyzyn083b0372015-12-04 10:59:45 -0800897 }
Mark Salyzyn7545b472016-04-11 14:03:48 -0700898 g_devCount++;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800899 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800900 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800901 break;
902
903 case 'B':
Traian Schiau59763032015-04-10 15:51:39 +0300904 g_printBinary = 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800905 break;
906
907 case 'f':
Mark Salyzyn9812fc42015-10-06 08:59:02 -0700908 if ((tail_time == log_time::EPOCH) && (tail_lines == 0)) {
Mark Salyzynf3555d92015-05-27 07:39:56 -0700909 tail_time = lastLogTime(optarg);
910 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800911 // redirect output to a file
Traian Schiau59763032015-04-10 15:51:39 +0300912 g_outputFileName = optarg;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800913 break;
914
915 case 'r':
Traian Schiau59763032015-04-10 15:51:39 +0300916 if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
917 logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800918 }
919 break;
920
921 case 'n':
Traian Schiau59763032015-04-10 15:51:39 +0300922 if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
923 logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800924 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800925 break;
926
927 case 'v':
928 err = setLogFormat (optarg);
929 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300930 logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800931 }
Mark Salyzyne1f20042015-05-06 08:40:40 -0700932 hasSetLogFormat |= err;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800933 break;
934
935 case 'Q':
936 /* this is a *hidden* option used to start a version of logcat */
937 /* in an emulated device only. it basically looks for androidboot.logcat= */
938 /* on the kernel command line. If something is found, it extracts a log filter */
939 /* and uses it to run the program. If nothing is found, the program should */
940 /* quit immediately */
941#define KERNEL_OPTION "androidboot.logcat="
942#define CONSOLE_OPTION "androidboot.console="
943 {
944 int fd;
945 char* logcat;
946 char* console;
947 int force_exit = 1;
948 static char cmdline[1024];
949
950 fd = open("/proc/cmdline", O_RDONLY);
951 if (fd >= 0) {
952 int n = read(fd, cmdline, sizeof(cmdline)-1 );
953 if (n < 0) n = 0;
954 cmdline[n] = 0;
955 close(fd);
956 } else {
957 cmdline[0] = 0;
958 }
959
960 logcat = strstr( cmdline, KERNEL_OPTION );
961 console = strstr( cmdline, CONSOLE_OPTION );
962 if (logcat != NULL) {
963 char* p = logcat + sizeof(KERNEL_OPTION)-1;;
964 char* q = strpbrk( p, " \t\n\r" );;
965
966 if (q != NULL)
967 *q = 0;
968
969 forceFilters = p;
970 force_exit = 0;
971 }
972 /* if nothing found or invalid filters, exit quietly */
Traian Schiau59763032015-04-10 15:51:39 +0300973 if (force_exit) {
974 return EXIT_SUCCESS;
975 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800976
977 /* redirect our output to the emulator console */
978 if (console) {
979 char* p = console + sizeof(CONSOLE_OPTION)-1;
980 char* q = strpbrk( p, " \t\n\r" );
981 char devname[64];
982 int len;
983
984 if (q != NULL) {
985 len = q - p;
986 } else
987 len = strlen(p);
988
989 len = snprintf( devname, sizeof(devname), "/dev/%.*s", len, p );
990 fprintf(stderr, "logcat using %s (%d)\n", devname, len);
991 if (len < (int)sizeof(devname)) {
992 fd = open( devname, O_WRONLY );
993 if (fd >= 0) {
994 dup2(fd, 1);
995 dup2(fd, 2);
996 close(fd);
997 }
998 }
999 }
1000 }
1001 break;
1002
Mark Salyzyn34facab2014-02-06 14:48:50 -08001003 case 'S':
1004 printStatistics = 1;
1005 break;
1006
padarshr0040c332016-07-22 17:12:16 +05301007 case 'w':
1008 g_logDumpEnabled = true;
1009 g_outputPartitionName = optarg;
1010 break;
1011
Traian Schiau59763032015-04-10 15:51:39 +03001012 case ':':
1013 logcat_panic(true, "Option -%c needs an argument\n", optopt);
1014 break;
1015
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001016 default:
Traian Schiau59763032015-04-10 15:51:39 +03001017 logcat_panic(true, "Unrecognized Option %c\n", optopt);
1018 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001019 }
1020 }
1021
Casey Dahlin1164ef62016-03-17 14:04:52 -07001022 if (g_maxCount && got_t) {
Mark Salyzyndf42ce42016-03-30 12:38:29 -07001023 logcat_panic(true, "Cannot use -m (--max-count) and -t together\n");
Casey Dahlin1164ef62016-03-17 14:04:52 -07001024 }
Mark Salyzyn3bef8972016-03-30 09:38:31 -07001025 if (g_printItAnyways && (!g_regex || !g_maxCount)) {
1026 // One day it would be nice if --print -v color and --regex <expr>
1027 // could play with each other and show regex highlighted content.
1028 fprintf(stderr, "WARNING: "
1029 "--print ignored, to be used in combination with\n"
1030 " "
1031 "--regex <expr> and --max-count <N>\n");
1032 g_printItAnyways = false;
1033 }
Casey Dahlin1164ef62016-03-17 14:04:52 -07001034
Joe Onorato6fa09a02010-02-26 10:04:23 -08001035 if (!devices) {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -08001036 dev = devices = new log_device_t("main", false);
Traian Schiau59763032015-04-10 15:51:39 +03001037 g_devCount = 1;
Mark Salyzyn95132e92013-11-22 10:55:48 -08001038 if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -08001039 dev = dev->next = new log_device_t("system", false);
Traian Schiau59763032015-04-10 15:51:39 +03001040 g_devCount++;
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -08001041 }
Mark Salyzyn99f47a92014-04-07 14:58:08 -07001042 if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -08001043 dev = dev->next = new log_device_t("crash", false);
Traian Schiau59763032015-04-10 15:51:39 +03001044 g_devCount++;
Mark Salyzyn99f47a92014-04-07 14:58:08 -07001045 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001046 }
1047
Traian Schiau59763032015-04-10 15:51:39 +03001048 if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
1049 logcat_panic(true, "-r requires -f as well\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001050 }
1051
Traian Schiau59763032015-04-10 15:51:39 +03001052 setupOutput();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001053
1054 if (hasSetLogFormat == 0) {
1055 const char* logFormat = getenv("ANDROID_PRINTF_LOG");
1056
1057 if (logFormat != NULL) {
1058 err = setLogFormat(logFormat);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001059 if (err < 0) {
Mark Salyzyn95132e92013-11-22 10:55:48 -08001060 fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001061 logFormat);
1062 }
Mark Salyzyn649fc602014-09-16 09:15:15 -07001063 } else {
1064 setLogFormat("threadtime");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001065 }
1066 }
1067
1068 if (forceFilters) {
1069 err = android_log_addFilterString(g_logformat, forceFilters);
1070 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +03001071 logcat_panic(false, "Invalid filter expression in logcat args\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001072 }
1073 } else if (argc == optind) {
1074 // Add from environment variable
1075 char *env_tags_orig = getenv("ANDROID_LOG_TAGS");
1076
1077 if (env_tags_orig != NULL) {
1078 err = android_log_addFilterString(g_logformat, env_tags_orig);
1079
Mark Salyzyn95132e92013-11-22 10:55:48 -08001080 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +03001081 logcat_panic(true,
1082 "Invalid filter expression in ANDROID_LOG_TAGS\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001083 }
1084 }
1085 } else {
1086 // Add from commandline
1087 for (int i = optind ; i < argc ; i++) {
1088 err = android_log_addFilterString(g_logformat, argv[i]);
1089
Mark Salyzyn95132e92013-11-22 10:55:48 -08001090 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +03001091 logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001092 }
1093 }
1094 }
1095
Joe Onorato6fa09a02010-02-26 10:04:23 -08001096 dev = devices;
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001097 if (tail_time != log_time::EPOCH) {
Kristian Monsen562e5132015-06-05 14:10:12 -07001098 logger_list = android_logger_list_alloc_time(mode, tail_time, pid);
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001099 } else {
Kristian Monsen562e5132015-06-05 14:10:12 -07001100 logger_list = android_logger_list_alloc(mode, tail_lines, pid);
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001101 }
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001102 const char *openDeviceFail = NULL;
1103 const char *clearFail = NULL;
1104 const char *setSizeFail = NULL;
1105 const char *getSizeFail = NULL;
1106 // We have three orthogonal actions below to clear, set log size and
1107 // get log size. All sharing the same iteration loop.
Joe Onorato6fa09a02010-02-26 10:04:23 -08001108 while (dev) {
Mark Salyzyn95132e92013-11-22 10:55:48 -08001109 dev->logger_list = logger_list;
1110 dev->logger = android_logger_open(logger_list,
1111 android_name_to_log_id(dev->device));
1112 if (!dev->logger) {
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001113 openDeviceFail = openDeviceFail ?: dev->device;
1114 dev = dev->next;
1115 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001116 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001117
1118 if (clearLog) {
Mark Salyzync8699592016-06-06 14:56:00 -07001119 if (g_outputFileName) {
1120 int maxRotationCountDigits =
1121 (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
1122
1123 for (int i = g_maxRotatedLogs ; i >= 0 ; --i) {
1124 char *file;
1125
1126 if (i == 0) {
1127 asprintf(&file, "%s", g_outputFileName);
1128 } else {
1129 asprintf(&file, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
1130 }
1131
1132 if (!file) {
1133 perror("while clearing log files");
1134 clearFail = clearFail ?: dev->device;
1135 break;
1136 }
1137
1138 err = unlink(file);
1139
1140 if (err < 0 && errno != ENOENT && clearFail == NULL) {
1141 perror("while clearing log files");
1142 clearFail = dev->device;
1143 }
1144
1145 free(file);
1146 }
1147 } else if (android_logger_clear(dev->logger)) {
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001148 clearFail = clearFail ?: dev->device;
Joe Onorato6fa09a02010-02-26 10:04:23 -08001149 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001150 }
1151
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001152 if (setLogSize) {
1153 if (android_logger_set_log_size(dev->logger, setLogSize)) {
1154 setSizeFail = setSizeFail ?: dev->device;
1155 }
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001156 }
1157
Joe Onorato6fa09a02010-02-26 10:04:23 -08001158 if (getLogSize) {
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001159 long size = android_logger_get_log_size(dev->logger);
1160 long readable = android_logger_get_log_readable_size(dev->logger);
Joe Onorato6fa09a02010-02-26 10:04:23 -08001161
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001162 if ((size < 0) || (readable < 0)) {
1163 getSizeFail = getSizeFail ?: dev->device;
1164 } else {
1165 printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
1166 "max entry is %db, max payload is %db\n", dev->device,
1167 value_of_size(size), multiplier_of_size(size),
1168 value_of_size(readable), multiplier_of_size(readable),
1169 (int) LOGGER_ENTRY_MAX_LEN,
1170 (int) LOGGER_ENTRY_MAX_PAYLOAD);
Joe Onorato6fa09a02010-02-26 10:04:23 -08001171 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001172 }
1173
1174 dev = dev->next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001175 }
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001176 // report any errors in the above loop and exit
1177 if (openDeviceFail) {
1178 logcat_panic(false, "Unable to open log device '%s'\n", openDeviceFail);
1179 }
1180 if (clearFail) {
1181 logcat_panic(false, "failed to clear the '%s' log\n", clearFail);
1182 }
1183 if (setSizeFail) {
1184 logcat_panic(false, "failed to set the '%s' log size\n", setSizeFail);
1185 }
1186 if (getSizeFail) {
1187 logcat_panic(false, "failed to get the readable '%s' log size",
1188 getSizeFail);
1189 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001190
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001191 if (setPruneList) {
Traian Schiau59763032015-04-10 15:51:39 +03001192 size_t len = strlen(setPruneList);
1193 /*extra 32 bytes are needed by android_logger_set_prune_list */
1194 size_t bLen = len + 32;
1195 char *buf = NULL;
1196 if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
1197 buf[len] = '\0';
1198 if (android_logger_set_prune_list(logger_list, buf, bLen)) {
1199 logcat_panic(false, "failed to set the prune list");
1200 }
1201 free(buf);
1202 } else {
1203 logcat_panic(false, "failed to set the prune list (alloc)");
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001204 }
1205 }
1206
Mark Salyzyn1c950472014-04-01 17:19:47 -07001207 if (printStatistics || getPruneList) {
Mark Salyzyn34facab2014-02-06 14:48:50 -08001208 size_t len = 8192;
1209 char *buf;
1210
Mark Salyzyn083b0372015-12-04 10:59:45 -08001211 for (int retry = 32;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001212 (retry >= 0) && ((buf = new char [len]));
Traian Schiau59763032015-04-10 15:51:39 +03001213 delete [] buf, buf = NULL, --retry) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001214 if (getPruneList) {
1215 android_logger_get_prune_list(logger_list, buf, len);
1216 } else {
1217 android_logger_get_statistics(logger_list, buf, len);
1218 }
Mark Salyzyn34facab2014-02-06 14:48:50 -08001219 buf[len-1] = '\0';
Traian Schiau59763032015-04-10 15:51:39 +03001220 if (atol(buf) < 3) {
Mark Salyzyn34facab2014-02-06 14:48:50 -08001221 delete [] buf;
1222 buf = NULL;
1223 break;
1224 }
Traian Schiau59763032015-04-10 15:51:39 +03001225 size_t ret = atol(buf) + 1;
1226 if (ret <= len) {
1227 len = ret;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001228 break;
1229 }
Traian Schiau59763032015-04-10 15:51:39 +03001230 len = ret;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001231 }
1232
1233 if (!buf) {
Traian Schiau59763032015-04-10 15:51:39 +03001234 logcat_panic(false, "failed to read data");
Mark Salyzyn34facab2014-02-06 14:48:50 -08001235 }
1236
1237 // remove trailing FF
1238 char *cp = buf + len - 1;
1239 *cp = '\0';
1240 bool truncated = *--cp != '\f';
1241 if (!truncated) {
1242 *cp = '\0';
1243 }
1244
1245 // squash out the byte count
1246 cp = buf;
1247 if (!truncated) {
Mark Salyzyn22e287d2014-03-21 13:12:16 -07001248 while (isdigit(*cp)) {
1249 ++cp;
1250 }
1251 if (*cp == '\n') {
Mark Salyzyn34facab2014-02-06 14:48:50 -08001252 ++cp;
1253 }
1254 }
1255
1256 printf("%s", cp);
1257 delete [] buf;
Traian Schiau59763032015-04-10 15:51:39 +03001258 return EXIT_SUCCESS;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001259 }
1260
1261
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001262 if (getLogSize) {
Traian Schiau59763032015-04-10 15:51:39 +03001263 return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001264 }
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001265 if (setLogSize || setPruneList) {
Traian Schiau59763032015-04-10 15:51:39 +03001266 return EXIT_SUCCESS;
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001267 }
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -08001268 if (clearLog) {
Traian Schiau59763032015-04-10 15:51:39 +03001269 return EXIT_SUCCESS;
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -08001270 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001271
1272 //LOG_EVENT_INT(10, 12345);
1273 //LOG_EVENT_LONG(11, 0x1122334455667788LL);
1274 //LOG_EVENT_STRING(0, "whassup, doc?");
1275
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001276 dev = NULL;
Mark Salyzyn5f6738a2015-02-27 13:41:34 -08001277 log_device_t unexpected("unexpected", false);
Casey Dahlin1164ef62016-03-17 14:04:52 -07001278
Mark Salyzyndf42ce42016-03-30 12:38:29 -07001279 while (!g_maxCount || (g_printCount < g_maxCount)) {
Mark Salyzyn95132e92013-11-22 10:55:48 -08001280 struct log_msg log_msg;
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001281 log_device_t* d;
Mark Salyzyn95132e92013-11-22 10:55:48 -08001282 int ret = android_logger_list_read(logger_list, &log_msg);
1283
1284 if (ret == 0) {
Traian Schiau59763032015-04-10 15:51:39 +03001285 logcat_panic(false, "read: unexpected EOF!\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001286 }
1287
1288 if (ret < 0) {
1289 if (ret == -EAGAIN) {
1290 break;
1291 }
1292
1293 if (ret == -EIO) {
Traian Schiau59763032015-04-10 15:51:39 +03001294 logcat_panic(false, "read: unexpected EOF!\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001295 }
1296 if (ret == -EINVAL) {
Traian Schiau59763032015-04-10 15:51:39 +03001297 logcat_panic(false, "read: unexpected length.\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001298 }
Traian Schiau59763032015-04-10 15:51:39 +03001299 logcat_panic(false, "logcat read failure");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001300 }
1301
Mark Salyzyn083b0372015-12-04 10:59:45 -08001302 for (d = devices; d; d = d->next) {
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001303 if (android_name_to_log_id(d->device) == log_msg.id()) {
Mark Salyzyn95132e92013-11-22 10:55:48 -08001304 break;
1305 }
1306 }
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001307 if (!d) {
Traian Schiau59763032015-04-10 15:51:39 +03001308 g_devCount = 2; // set to Multiple
Mark Salyzyn9421b0c2015-02-26 14:33:35 -08001309 d = &unexpected;
1310 d->binary = log_msg.id() == LOG_ID_EVENTS;
Mark Salyzyn95132e92013-11-22 10:55:48 -08001311 }
1312
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001313 if (dev != d) {
1314 dev = d;
Traian Schiau59763032015-04-10 15:51:39 +03001315 maybePrintStart(dev, printDividers);
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001316 }
Traian Schiau59763032015-04-10 15:51:39 +03001317 if (g_printBinary) {
1318 printBinary(&log_msg);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001319 } else {
Traian Schiau59763032015-04-10 15:51:39 +03001320 processBuffer(dev, &log_msg);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001321 }
1322 }
1323
1324 android_logger_list_free(logger_list);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001325
Traian Schiau59763032015-04-10 15:51:39 +03001326 return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001327}