blob: 729e704226c31152c9121692da9c1ce2ca8484ac [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>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070030#include <cutils/sched_policy.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080031#include <cutils/sockets.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070032#include <log/event_tag_map.h>
Mark Salyzyn95132e92013-11-22 10:55:48 -080033#include <log/log.h>
Mark Salyzynfa3716b2014-02-14 16:05:05 -080034#include <log/log_read.h>
Colin Cross9227bd32013-07-23 16:59:20 -070035#include <log/logd.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070036#include <log/logger.h>
Colin Cross9227bd32013-07-23 16:59:20 -070037#include <log/logprint.h>
Elliott Hughesb9e53b42016-02-17 11:58:01 -080038#include <system/thread_defs.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080039
Casey Dahlindc42a872016-03-17 16:18:55 -070040#include <pcrecpp.h>
41
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080042#define DEFAULT_MAX_ROTATED_LOGS 4
43
44static AndroidLogFormat * g_logformat;
45
46/* logd prefixes records with a length field */
47#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
48
Joe Onorato6fa09a02010-02-26 10:04:23 -080049struct log_device_t {
Mark Salyzyn95132e92013-11-22 10:55:48 -080050 const char* device;
Joe Onorato6fa09a02010-02-26 10:04:23 -080051 bool binary;
Mark Salyzyn95132e92013-11-22 10:55:48 -080052 struct logger *logger;
53 struct logger_list *logger_list;
Joe Onorato6fa09a02010-02-26 10:04:23 -080054 bool printed;
Joe Onorato6fa09a02010-02-26 10:04:23 -080055
Joe Onorato6fa09a02010-02-26 10:04:23 -080056 log_device_t* next;
57
Mark Salyzyn5f6738a2015-02-27 13:41:34 -080058 log_device_t(const char* d, bool b) {
Joe Onorato6fa09a02010-02-26 10:04:23 -080059 device = d;
60 binary = b;
Joe Onorato6fa09a02010-02-26 10:04:23 -080061 next = NULL;
62 printed = false;
Traian Schiau59763032015-04-10 15:51:39 +030063 logger = NULL;
64 logger_list = NULL;
Joe Onorato6fa09a02010-02-26 10:04:23 -080065 }
Joe Onorato6fa09a02010-02-26 10:04:23 -080066};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080067
68namespace android {
69
70/* Global Variables */
71
72static const char * g_outputFileName = NULL;
Traian Schiau59763032015-04-10 15:51:39 +030073// 0 means "no log rotation"
74static size_t g_logRotateSizeKBytes = 0;
75// 0 means "unbounded"
76static size_t g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080077static int g_outFD = -1;
Traian Schiau59763032015-04-10 15:51:39 +030078static size_t g_outByteCount = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080079static int g_printBinary = 0;
Mark Salyzyn9421b0c2015-02-26 14:33:35 -080080static int g_devCount = 0; // >1 means multiple
Casey Dahlindc42a872016-03-17 16:18:55 -070081static pcrecpp::RE* g_regex;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080082
Traian Schiau59763032015-04-10 15:51:39 +030083__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
84
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080085static int openLogFile (const char *pathname)
86{
Edwin Vane80b221c2012-08-13 12:55:07 -040087 return open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080088}
89
90static void rotateLogs()
91{
92 int err;
93
94 // Can't rotate logs if we're not outputting to a file
95 if (g_outputFileName == NULL) {
96 return;
97 }
98
99 close(g_outFD);
100
Aristidis Papaioannoueba73442014-10-16 22:19:55 -0700101 // Compute the maximum number of digits needed to count up to g_maxRotatedLogs in decimal.
102 // eg: g_maxRotatedLogs == 30 -> log10(30) == 1.477 -> maxRotationCountDigits == 2
103 int maxRotationCountDigits =
104 (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
105
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800106 for (int i = g_maxRotatedLogs ; i > 0 ; i--) {
107 char *file0, *file1;
108
Aristidis Papaioannoueba73442014-10-16 22:19:55 -0700109 asprintf(&file1, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800110
111 if (i - 1 == 0) {
112 asprintf(&file0, "%s", g_outputFileName);
113 } else {
Aristidis Papaioannoueba73442014-10-16 22:19:55 -0700114 asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800115 }
116
Traian Schiau59763032015-04-10 15:51:39 +0300117 if (!file0 || !file1) {
118 perror("while rotating log files");
119 break;
120 }
121
122 err = rename(file0, file1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800123
124 if (err < 0 && errno != ENOENT) {
125 perror("while rotating log files");
126 }
127
128 free(file1);
129 free(file0);
130 }
131
Traian Schiau59763032015-04-10 15:51:39 +0300132 g_outFD = openLogFile(g_outputFileName);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800133
134 if (g_outFD < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300135 logcat_panic(false, "couldn't open output file");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800136 }
137
138 g_outByteCount = 0;
139
140}
141
Mark Salyzyn95132e92013-11-22 10:55:48 -0800142void printBinary(struct log_msg *buf)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800143{
Mark Salyzyn95132e92013-11-22 10:55:48 -0800144 size_t size = buf->len();
145
146 TEMP_FAILURE_RETRY(write(g_outFD, buf, size));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800147}
148
Casey Dahlindc42a872016-03-17 16:18:55 -0700149static bool regexOk(const AndroidLogEntry& entry, log_id_t id)
150{
151 if (! g_regex) {
152 return true;
153 }
154
155 if (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) {
156 return false;
157 }
158
159 std::string messageString(entry.message, entry.messageLen);
160
161 return g_regex->PartialMatch(messageString);
162}
163
Mark Salyzyn95132e92013-11-22 10:55:48 -0800164static void processBuffer(log_device_t* dev, struct log_msg *buf)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800165{
Mathias Agopian50844522010-03-17 16:10:26 -0700166 int bytesWritten = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800167 int err;
168 AndroidLogEntry entry;
169 char binaryMsgBuf[1024];
170
Joe Onorato6fa09a02010-02-26 10:04:23 -0800171 if (dev->binary) {
Mark Salyzyn9421b0c2015-02-26 14:33:35 -0800172 static bool hasOpenedEventTagMap = false;
173 static EventTagMap *eventTagMap = NULL;
174
175 if (!eventTagMap && !hasOpenedEventTagMap) {
176 eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
177 hasOpenedEventTagMap = true;
178 }
Mark Salyzyn95132e92013-11-22 10:55:48 -0800179 err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
Mark Salyzyn9421b0c2015-02-26 14:33:35 -0800180 eventTagMap,
Mark Salyzyn95132e92013-11-22 10:55:48 -0800181 binaryMsgBuf,
182 sizeof(binaryMsgBuf));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800183 //printf(">>> pri=%d len=%d msg='%s'\n",
184 // entry.priority, entry.messageLen, entry.message);
185 } else {
Mark Salyzyn95132e92013-11-22 10:55:48 -0800186 err = android_log_processLogBuffer(&buf->entry_v1, &entry);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800187 }
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800188 if (err < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800189 goto error;
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800190 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800191
Casey Dahlindc42a872016-03-17 16:18:55 -0700192 if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority) &&
193 regexOk(entry, buf->id())) {
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800194 bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
195
196 if (bytesWritten < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300197 logcat_panic(false, "output error");
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800198 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800199 }
200
201 g_outByteCount += bytesWritten;
202
Mark Salyzyn95132e92013-11-22 10:55:48 -0800203 if (g_logRotateSizeKBytes > 0
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800204 && (g_outByteCount / 1024) >= g_logRotateSizeKBytes
205 ) {
206 rotateLogs();
207 }
208
209error:
210 //fprintf (stderr, "Error processing record\n");
211 return;
212}
213
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800214static void maybePrintStart(log_device_t* dev, bool printDividers) {
215 if (!dev->printed || printDividers) {
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800216 if (g_devCount > 1 && !g_printBinary) {
217 char buf[1024];
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800218 snprintf(buf, sizeof(buf), "--------- %s %s\n",
219 dev->printed ? "switch to" : "beginning of",
Mark Salyzyn95132e92013-11-22 10:55:48 -0800220 dev->device);
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800221 if (write(g_outFD, buf, strlen(buf)) < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300222 logcat_panic(false, "output error");
Joe Onorato6fa09a02010-02-26 10:04:23 -0800223 }
224 }
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800225 dev->printed = true;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800226 }
227}
228
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800229static void setupOutput()
230{
231
232 if (g_outputFileName == NULL) {
233 g_outFD = STDOUT_FILENO;
234
235 } else {
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700236 if (set_sched_policy(0, SP_BACKGROUND) < 0) {
237 fprintf(stderr, "failed to set background scheduling policy\n");
238 }
239
240 struct sched_param param;
241 memset(&param, 0, sizeof(param));
242 if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
243 fprintf(stderr, "failed to set to batch scheduler\n");
244 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800245
Riley Andrewsaede9892015-06-08 23:36:34 -0700246 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
247 fprintf(stderr, "failed set to priority\n");
248 }
249
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800250 g_outFD = openLogFile (g_outputFileName);
251
252 if (g_outFD < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300253 logcat_panic(false, "couldn't open output file");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800254 }
255
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700256 struct stat statbuf;
Traian Schiau59763032015-04-10 15:51:39 +0300257 if (fstat(g_outFD, &statbuf) == -1) {
258 close(g_outFD);
259 logcat_panic(false, "couldn't get output file stat\n");
260 }
261
262 if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
263 close(g_outFD);
264 logcat_panic(false, "invalid output file stat\n");
265 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800266
267 g_outByteCount = statbuf.st_size;
268 }
269}
270
271static void show_help(const char *cmd)
272{
273 fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
274
275 fprintf(stderr, "options include:\n"
276 " -s Set default filter to silent.\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700277 " Like specifying filterspec '*:S'\n"
Mark Salyzynf3555d92015-05-27 07:39:56 -0700278 " -f <filename> Log to file. Default is stdout\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800279 " --file=<filename>\n"
Traian Schiau59763032015-04-10 15:51:39 +0300280 " -r <kbytes> Rotate log every kbytes. Requires -f\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800281 " --rotate_kbytes=<kbytes>\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800282 " -n <count> Sets max number of rotated logs to <count>, default 4\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800283 " --rotate_count=<count>\n"
284 " -v <format> Sets the log print format, where <format> is:\n"
285 " --format=<format>\n"
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700286 " brief color epoch long monotonic printable process raw\n"
Mark Salyzyn90e7af32015-12-07 16:52:42 -0800287 " tag thread threadtime time uid usec UTC year zone\n\n"
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800288 " -D print dividers between each log buffer\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800289 " --dividers\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800290 " -c clear (flush) the entire log and exit\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800291 " --clear\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800292 " -d dump the log and then exit (don't block)\n"
Casey Dahlindc42a872016-03-17 16:18:55 -0700293 " -e <expr> only print lines where the log message matches <expr>\n"
294 " --regex <expr> where <expr> is a regular expression\n"
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800295 " -t <count> print only the most recent <count> lines (implies -d)\n"
Mark Salyzyn190b7ac2014-09-01 10:41:33 -0700296 " -t '<time>' print most recent lines since specified time (implies -d)\n"
Mark Salyzyn5d3d1f12013-12-09 13:47:00 -0800297 " -T <count> print only the most recent <count> lines (does not imply -d)\n"
Mark Salyzyn190b7ac2014-09-01 10:41:33 -0700298 " -T '<time>' print most recent lines since specified time (not imply -d)\n"
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700299 " count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'\n"
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700300 " 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800301 " -g get the size of the log's ring buffer and exit\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800302 " --buffer_size\n"
303 " -G <size> set size of log ring buffer, may suffix with K or M.\n"
304 " --buffer_size=<size>\n"
Mark Salyzyn7c975ac2014-12-15 10:01:31 -0800305 " -L dump logs from prior to last reboot\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800306 " --last\n"
Mark Salyzyn083b0372015-12-04 10:59:45 -0800307 // Leave security (Device Owner only installations) and
308 // kernel (userdebug and eng) buffers undocumented.
Mark Salyzyn34facab2014-02-06 14:48:50 -0800309 " -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio',\n"
Mark Salyzyn083b0372015-12-04 10:59:45 -0800310 " --buffer=<buffer> 'events', 'crash', 'default' or 'all'. Multiple -b\n"
311 " parameters are allowed and results are interleaved. The\n"
312 " default is -b main -b system -b crash.\n"
Mark Salyzyn34facab2014-02-06 14:48:50 -0800313 " -B output the log in binary.\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800314 " --binary\n"
Mark Salyzynbbbe14f2014-04-11 13:49:43 -0700315 " -S output statistics.\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800316 " --statistics\n"
Mark Salyzynbbbe14f2014-04-11 13:49:43 -0700317 " -p print prune white and ~black list. Service is specified as\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800318 " --prune UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
Mark Salyzynbbbe14f2014-04-11 13:49:43 -0700319 " with ~, otherwise weighed for longevity if unadorned. All\n"
320 " other pruning activity is oldest first. Special case ~!\n"
321 " represents an automatic quicker pruning for the noisiest\n"
322 " UID as determined by the current statistics.\n"
323 " -P '<list> ...' set prune white and ~black list, using same format as\n"
Mark Salyzynf8bff872015-11-30 12:57:56 -0800324 " --prune='<list> ...' printed above. Must be quoted.\n"
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800325 " --pid=<pid> Only prints logs from the given pid.\n"
326 // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value
327 " --wrap Sleep for 2 hours or when buffer about to wrap whichever\n"
328 " comes first. Improves efficiency of polling by providing\n"
329 " an about-to-wrap wakeup.\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800330
331 fprintf(stderr,"\nfilterspecs are a series of \n"
332 " <tag>[:priority]\n\n"
333 "where <tag> is a log component tag (or * for all) and priority is:\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700334 " V Verbose (default for <tag>)\n"
335 " D Debug (default for '*')\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800336 " I Info\n"
337 " W Warn\n"
338 " E Error\n"
339 " F Fatal\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700340 " S Silent (suppress all output)\n"
341 "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
342 "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
343 "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
344 "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
345 "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
Mark Salyzyn649fc602014-09-16 09:15:15 -0700346 "or defaults to \"threadtime\"\n\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800347}
348
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800349static int setLogFormat(const char * formatString)
350{
351 static AndroidLogPrintFormat format;
352
353 format = android_log_formatFromString(formatString);
354
355 if (format == FORMAT_OFF) {
356 // FORMAT_OFF means invalid string
357 return -1;
358 }
359
Mark Salyzyne1f20042015-05-06 08:40:40 -0700360 return android_log_setPrintFormat(g_logformat, format);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800361}
362
Mark Salyzyn671e3432014-05-06 07:34:59 -0700363static const char multipliers[][2] = {
364 { "" },
365 { "K" },
366 { "M" },
367 { "G" }
368};
369
370static unsigned long value_of_size(unsigned long value)
371{
372 for (unsigned i = 0;
373 (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
374 value /= 1024, ++i) ;
375 return value;
376}
377
378static const char *multiplier_of_size(unsigned long value)
379{
380 unsigned i;
381 for (i = 0;
382 (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
383 value /= 1024, ++i) ;
384 return multipliers[i];
385}
386
Traian Schiau59763032015-04-10 15:51:39 +0300387/*String to unsigned int, returns -1 if it fails*/
388static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0,
389 size_t max = SIZE_MAX)
390{
Kristian Monsen562e5132015-06-05 14:10:12 -0700391 if (!ptr) {
Traian Schiau59763032015-04-10 15:51:39 +0300392 return false;
393 }
394
Kristian Monsen562e5132015-06-05 14:10:12 -0700395 char *endp;
396 errno = 0;
397 size_t ret = (size_t)strtoll(ptr, &endp, 0);
398
399 if (endp[0] || errno) {
400 return false;
401 }
402
403 if ((ret > max) || (ret < min)) {
Traian Schiau59763032015-04-10 15:51:39 +0300404 return false;
405 }
406
407 *val = ret;
408 return true;
409}
410
411static void logcat_panic(bool showHelp, const char *fmt, ...)
412{
Mark Salyzyn77d7e812015-04-13 09:27:57 -0700413 va_list args;
414 va_start(args, fmt);
415 vfprintf(stderr, fmt, args);
416 va_end(args);
Traian Schiau59763032015-04-10 15:51:39 +0300417
418 if (showHelp) {
419 show_help(getprogname());
420 }
421
422 exit(EXIT_FAILURE);
423}
424
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700425static char *parseTime(log_time &t, const char *cp) {
426
427 char *ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
428 if (ep) {
429 return ep;
430 }
Mark Salyzyn4cbed022015-08-31 15:53:41 -0700431 ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
432 if (ep) {
433 return ep;
434 }
435 return t.strptime(cp, "%s.%q");
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700436}
Mark Salyzynf3555d92015-05-27 07:39:56 -0700437
438// Find last logged line in gestalt of all matching existing output files
439static log_time lastLogTime(char *outputFileName) {
440 log_time retval(log_time::EPOCH);
441 if (!outputFileName) {
442 return retval;
443 }
444
Mark Salyzynba7a9a02015-12-01 15:57:25 -0800445 clockid_t clock_type = android_log_clockid();
446 log_time now(clock_type);
447 bool monotonic = clock_type == CLOCK_MONOTONIC;
Mark Salyzynf3555d92015-05-27 07:39:56 -0700448
449 std::string directory;
450 char *file = strrchr(outputFileName, '/');
451 if (!file) {
452 directory = ".";
453 file = outputFileName;
454 } else {
455 *file = '\0';
456 directory = outputFileName;
457 *file = '/';
458 ++file;
459 }
460 size_t len = strlen(file);
461 log_time modulo(0, NS_PER_SEC);
462 std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(directory.c_str()), closedir);
463 struct dirent *dp;
464 while ((dp = readdir(dir.get())) != NULL) {
465 if ((dp->d_type != DT_REG)
Mark Salyzynb6bee332015-09-08 08:56:32 -0700466 // If we are using realtime, check all files that match the
467 // basename for latest time. If we are using monotonic time
468 // then only check the main file because time cycles on
469 // every reboot.
470 || strncmp(dp->d_name, file, len + monotonic)
Mark Salyzynf3555d92015-05-27 07:39:56 -0700471 || (dp->d_name[len]
472 && ((dp->d_name[len] != '.')
473 || !isdigit(dp->d_name[len+1])))) {
474 continue;
475 }
476
477 std::string file_name = directory;
478 file_name += "/";
479 file_name += dp->d_name;
480 std::string file;
481 if (!android::base::ReadFileToString(file_name, &file)) {
482 continue;
483 }
484
485 bool found = false;
486 for (const auto& line : android::base::Split(file, "\n")) {
487 log_time t(log_time::EPOCH);
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700488 char *ep = parseTime(t, line.c_str());
Mark Salyzynf3555d92015-05-27 07:39:56 -0700489 if (!ep || (*ep != ' ')) {
490 continue;
491 }
492 // determine the time precision of the logs (eg: msec or usec)
493 for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
494 if (t.tv_nsec % (mod * 10)) {
495 modulo.tv_nsec = mod;
496 break;
497 }
498 }
499 // We filter any times later than current as we may not have the
500 // year stored with each log entry. Also, since it is possible for
501 // entries to be recorded out of order (very rare) we select the
502 // maximum we find just in case.
503 if ((t < now) && (t > retval)) {
504 retval = t;
505 found = true;
506 }
507 }
508 // We count on the basename file to be the definitive end, so stop here.
509 if (!dp->d_name[len] && found) {
510 break;
511 }
512 }
513 if (retval == log_time::EPOCH) {
514 return retval;
515 }
516 // tail_time prints matching or higher, round up by the modulo to prevent
517 // a replay of the last entry we have just checked.
518 retval += modulo;
519 return retval;
520}
521
Traian Schiau59763032015-04-10 15:51:39 +0300522} /* namespace android */
523
524
Joe Onorato6fa09a02010-02-26 10:04:23 -0800525int main(int argc, char **argv)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800526{
Traian Schiau59763032015-04-10 15:51:39 +0300527 using namespace android;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800528 int err;
529 int hasSetLogFormat = 0;
530 int clearLog = 0;
531 int getLogSize = 0;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800532 unsigned long setLogSize = 0;
533 int getPruneList = 0;
534 char *setPruneList = NULL;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800535 int printStatistics = 0;
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800536 int mode = ANDROID_LOG_RDONLY;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800537 const char *forceFilters = NULL;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800538 log_device_t* devices = NULL;
539 log_device_t* dev;
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800540 bool printDividers = false;
Mark Salyzyn95132e92013-11-22 10:55:48 -0800541 struct logger_list *logger_list;
Traian Schiau59763032015-04-10 15:51:39 +0300542 size_t tail_lines = 0;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800543 log_time tail_time(log_time::EPOCH);
Kristian Monsen562e5132015-06-05 14:10:12 -0700544 size_t pid = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800545
Mark Salyzyn65772ca2013-12-13 11:10:11 -0800546 signal(SIGPIPE, exit);
547
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800548 g_logformat = android_log_format_new();
549
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800550 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
Traian Schiau59763032015-04-10 15:51:39 +0300551 show_help(argv[0]);
552 return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800553 }
554
555 for (;;) {
556 int ret;
557
Kristian Monsen562e5132015-06-05 14:10:12 -0700558 int option_index = 0;
559 static const char pid_str[] = "pid";
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800560 static const char wrap_str[] = "wrap";
Kristian Monsen562e5132015-06-05 14:10:12 -0700561 static const struct option long_options[] = {
Mark Salyzynf8bff872015-11-30 12:57:56 -0800562 { "binary", no_argument, NULL, 'B' },
563 { "buffer", required_argument, NULL, 'b' },
564 { "buffer_size", optional_argument, NULL, 'g' },
565 { "clear", no_argument, NULL, 'c' },
566 { "dividers", no_argument, NULL, 'D' },
567 { "file", required_argument, NULL, 'f' },
568 { "format", required_argument, NULL, 'v' },
569 { "last", no_argument, NULL, 'L' },
Kristian Monsen562e5132015-06-05 14:10:12 -0700570 { pid_str, required_argument, NULL, 0 },
Mark Salyzynf8bff872015-11-30 12:57:56 -0800571 { "prune", optional_argument, NULL, 'p' },
Casey Dahlindc42a872016-03-17 16:18:55 -0700572 { "regex", required_argument, NULL, 'e' },
Mark Salyzynf8bff872015-11-30 12:57:56 -0800573 { "rotate_count", required_argument, NULL, 'n' },
574 { "rotate_kbytes", required_argument, NULL, 'r' },
575 { "statistics", no_argument, NULL, 'S' },
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800576 // support, but ignore and do not document, the optional argument
577 { wrap_str, optional_argument, NULL, 0 },
Kristian Monsen562e5132015-06-05 14:10:12 -0700578 { NULL, 0, NULL, 0 }
579 };
580
Casey Dahlindc42a872016-03-17 16:18:55 -0700581 ret = getopt_long(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:e:",
Kristian Monsen562e5132015-06-05 14:10:12 -0700582 long_options, &option_index);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800583
584 if (ret < 0) {
585 break;
586 }
587
Kristian Monsen562e5132015-06-05 14:10:12 -0700588 switch (ret) {
589 case 0:
590 // One of the long options
591 if (long_options[option_index].name == pid_str) {
592 // ToDo: determine runtime PID_MAX?
593 if (!getSizeTArg(optarg, &pid, 1)) {
594 logcat_panic(true, "%s %s out of range\n",
595 long_options[option_index].name, optarg);
596 }
597 break;
598 }
Mark Salyzyn41ba25f2015-11-30 13:48:56 -0800599 if (long_options[option_index].name == wrap_str) {
600 mode |= ANDROID_LOG_WRAP |
601 ANDROID_LOG_RDONLY |
602 ANDROID_LOG_NONBLOCK;
603 // ToDo: implement API that supports setting a wrap timeout
604 size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
605 if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
606 logcat_panic(true, "%s %s out of range\n",
607 long_options[option_index].name, optarg);
608 }
609 if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
610 fprintf(stderr,
611 "WARNING: %s %u seconds, ignoring %zu\n",
612 long_options[option_index].name,
613 ANDROID_LOG_WRAP_DEFAULT_TIMEOUT, dummy);
614 }
615 break;
616 }
Kristian Monsen562e5132015-06-05 14:10:12 -0700617 break;
618
Mark Salyzyn95132e92013-11-22 10:55:48 -0800619 case 's':
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800620 // default to all silent
621 android_log_addFilterRule(g_logformat, "*:s");
622 break;
623
624 case 'c':
625 clearLog = 1;
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800626 mode |= ANDROID_LOG_WRONLY;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800627 break;
628
Mark Salyzyn7c975ac2014-12-15 10:01:31 -0800629 case 'L':
630 mode |= ANDROID_LOG_PSTORE;
631 break;
632
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800633 case 'd':
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800634 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800635 break;
636
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800637 case 't':
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800638 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
Mark Salyzyn5d3d1f12013-12-09 13:47:00 -0800639 /* FALLTHRU */
640 case 'T':
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800641 if (strspn(optarg, "0123456789") != strlen(optarg)) {
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700642 char *cp = parseTime(tail_time, optarg);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800643 if (!cp) {
Mark Salyzynf28f6a92015-08-31 08:01:33 -0700644 logcat_panic(false, "-%c \"%s\" not in time format\n",
645 ret, optarg);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800646 }
647 if (*cp) {
648 char c = *cp;
649 *cp = '\0';
650 fprintf(stderr,
651 "WARNING: -%c \"%s\"\"%c%s\" time truncated\n",
652 ret, optarg, c, cp + 1);
653 *cp = c;
654 }
655 } else {
Traian Schiau59763032015-04-10 15:51:39 +0300656 if (!getSizeTArg(optarg, &tail_lines, 1)) {
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800657 fprintf(stderr,
658 "WARNING: -%c %s invalid, setting to 1\n",
659 ret, optarg);
660 tail_lines = 1;
661 }
662 }
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800663 break;
664
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800665 case 'D':
666 printDividers = true;
667 break;
668
Casey Dahlindc42a872016-03-17 16:18:55 -0700669 case 'e':
670 g_regex = new pcrecpp::RE(optarg);
671 break;
672
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800673 case 'g':
Mark Salyzynf8bff872015-11-30 12:57:56 -0800674 if (!optarg) {
675 getLogSize = 1;
676 break;
677 }
678 // FALLTHRU
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800679
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800680 case 'G': {
Traian Schiau59763032015-04-10 15:51:39 +0300681 char *cp;
682 if (strtoll(optarg, &cp, 0) > 0) {
683 setLogSize = strtoll(optarg, &cp, 0);
684 } else {
685 setLogSize = 0;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800686 }
687
688 switch(*cp) {
689 case 'g':
690 case 'G':
691 setLogSize *= 1024;
692 /* FALLTHRU */
693 case 'm':
694 case 'M':
695 setLogSize *= 1024;
696 /* FALLTHRU */
697 case 'k':
698 case 'K':
699 setLogSize *= 1024;
700 /* FALLTHRU */
701 case '\0':
702 break;
703
704 default:
705 setLogSize = 0;
706 }
707
708 if (!setLogSize) {
709 fprintf(stderr, "ERROR: -G <num><multiplier>\n");
Traian Schiau59763032015-04-10 15:51:39 +0300710 return EXIT_FAILURE;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800711 }
712 }
713 break;
714
715 case 'p':
Mark Salyzynf8bff872015-11-30 12:57:56 -0800716 if (!optarg) {
717 getPruneList = 1;
718 break;
719 }
720 // FALLTHRU
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800721
722 case 'P':
723 setPruneList = optarg;
724 break;
725
Joe Onorato6fa09a02010-02-26 10:04:23 -0800726 case 'b': {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800727 if (strcmp(optarg, "default") == 0) {
728 for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
729 switch (i) {
730 case LOG_ID_SECURITY:
731 case LOG_ID_EVENTS:
732 continue;
733 case LOG_ID_MAIN:
734 case LOG_ID_SYSTEM:
735 case LOG_ID_CRASH:
736 break;
737 default:
738 continue;
739 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800740
Mark Salyzynd0bd1b12014-10-10 15:25:38 -0700741 const char *name = android_log_id_to_name((log_id_t)i);
742 log_id_t log_id = android_name_to_log_id(name);
743
744 if (log_id != (log_id_t)i) {
745 continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800746 }
Mark Salyzynd0bd1b12014-10-10 15:25:38 -0700747
Mark Salyzyn083b0372015-12-04 10:59:45 -0800748 bool found = false;
749 for (dev = devices; dev; dev = dev->next) {
750 if (!strcmp(optarg, dev->device)) {
751 found = true;
752 break;
753 }
754 if (!dev->next) {
755 break;
756 }
757 }
758 if (found) {
759 break;
760 }
761
762 log_device_t* d = new log_device_t(name, false);
763
764 if (dev) {
765 dev->next = d;
766 dev = d;
767 } else {
768 devices = dev = d;
769 }
770 g_devCount++;
771 }
772 break;
773 }
774
775 if (strcmp(optarg, "all") == 0) {
776 for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
777 const char *name = android_log_id_to_name((log_id_t)i);
778 log_id_t log_id = android_name_to_log_id(name);
779
780 if (log_id != (log_id_t)i) {
781 continue;
782 }
783
784 bool found = false;
785 for (dev = devices; dev; dev = dev->next) {
786 if (!strcmp(optarg, dev->device)) {
787 found = true;
788 break;
789 }
790 if (!dev->next) {
791 break;
792 }
793 }
794 if (found) {
795 break;
796 }
797
798 bool binary = !strcmp(name, "events") ||
799 !strcmp(name, "security");
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800800 log_device_t* d = new log_device_t(name, binary);
Mark Salyzynd0bd1b12014-10-10 15:25:38 -0700801
802 if (dev) {
803 dev->next = d;
804 dev = d;
805 } else {
806 devices = dev = d;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800807 }
Traian Schiau59763032015-04-10 15:51:39 +0300808 g_devCount++;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800809 }
810 break;
811 }
812
Mark Salyzyn083b0372015-12-04 10:59:45 -0800813 bool binary = !(strcmp(optarg, "events") &&
814 strcmp(optarg, "security"));
Joe Onorato6fa09a02010-02-26 10:04:23 -0800815
816 if (devices) {
817 dev = devices;
818 while (dev->next) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800819 if (!strcmp(optarg, dev->device)) {
820 dev = NULL;
821 break;
822 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800823 dev = dev->next;
824 }
Mark Salyzyn083b0372015-12-04 10:59:45 -0800825 if (dev) {
826 dev->next = new log_device_t(optarg, binary);
827 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800828 } else {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800829 devices = new log_device_t(optarg, binary);
Joe Onorato6fa09a02010-02-26 10:04:23 -0800830 }
Traian Schiau59763032015-04-10 15:51:39 +0300831 g_devCount++;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800832 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800833 break;
834
835 case 'B':
Traian Schiau59763032015-04-10 15:51:39 +0300836 g_printBinary = 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800837 break;
838
839 case 'f':
Mark Salyzyn9812fc42015-10-06 08:59:02 -0700840 if ((tail_time == log_time::EPOCH) && (tail_lines == 0)) {
Mark Salyzynf3555d92015-05-27 07:39:56 -0700841 tail_time = lastLogTime(optarg);
842 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800843 // redirect output to a file
Traian Schiau59763032015-04-10 15:51:39 +0300844 g_outputFileName = optarg;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800845 break;
846
847 case 'r':
Traian Schiau59763032015-04-10 15:51:39 +0300848 if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
849 logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800850 }
851 break;
852
853 case 'n':
Traian Schiau59763032015-04-10 15:51:39 +0300854 if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
855 logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800856 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800857 break;
858
859 case 'v':
860 err = setLogFormat (optarg);
861 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300862 logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800863 }
Mark Salyzyne1f20042015-05-06 08:40:40 -0700864 hasSetLogFormat |= err;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800865 break;
866
867 case 'Q':
868 /* this is a *hidden* option used to start a version of logcat */
869 /* in an emulated device only. it basically looks for androidboot.logcat= */
870 /* on the kernel command line. If something is found, it extracts a log filter */
871 /* and uses it to run the program. If nothing is found, the program should */
872 /* quit immediately */
873#define KERNEL_OPTION "androidboot.logcat="
874#define CONSOLE_OPTION "androidboot.console="
875 {
876 int fd;
877 char* logcat;
878 char* console;
879 int force_exit = 1;
880 static char cmdline[1024];
881
882 fd = open("/proc/cmdline", O_RDONLY);
883 if (fd >= 0) {
884 int n = read(fd, cmdline, sizeof(cmdline)-1 );
885 if (n < 0) n = 0;
886 cmdline[n] = 0;
887 close(fd);
888 } else {
889 cmdline[0] = 0;
890 }
891
892 logcat = strstr( cmdline, KERNEL_OPTION );
893 console = strstr( cmdline, CONSOLE_OPTION );
894 if (logcat != NULL) {
895 char* p = logcat + sizeof(KERNEL_OPTION)-1;;
896 char* q = strpbrk( p, " \t\n\r" );;
897
898 if (q != NULL)
899 *q = 0;
900
901 forceFilters = p;
902 force_exit = 0;
903 }
904 /* if nothing found or invalid filters, exit quietly */
Traian Schiau59763032015-04-10 15:51:39 +0300905 if (force_exit) {
906 return EXIT_SUCCESS;
907 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800908
909 /* redirect our output to the emulator console */
910 if (console) {
911 char* p = console + sizeof(CONSOLE_OPTION)-1;
912 char* q = strpbrk( p, " \t\n\r" );
913 char devname[64];
914 int len;
915
916 if (q != NULL) {
917 len = q - p;
918 } else
919 len = strlen(p);
920
921 len = snprintf( devname, sizeof(devname), "/dev/%.*s", len, p );
922 fprintf(stderr, "logcat using %s (%d)\n", devname, len);
923 if (len < (int)sizeof(devname)) {
924 fd = open( devname, O_WRONLY );
925 if (fd >= 0) {
926 dup2(fd, 1);
927 dup2(fd, 2);
928 close(fd);
929 }
930 }
931 }
932 }
933 break;
934
Mark Salyzyn34facab2014-02-06 14:48:50 -0800935 case 'S':
936 printStatistics = 1;
937 break;
938
Traian Schiau59763032015-04-10 15:51:39 +0300939 case ':':
940 logcat_panic(true, "Option -%c needs an argument\n", optopt);
941 break;
942
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800943 default:
Traian Schiau59763032015-04-10 15:51:39 +0300944 logcat_panic(true, "Unrecognized Option %c\n", optopt);
945 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800946 }
947 }
948
Joe Onorato6fa09a02010-02-26 10:04:23 -0800949 if (!devices) {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800950 dev = devices = new log_device_t("main", false);
Traian Schiau59763032015-04-10 15:51:39 +0300951 g_devCount = 1;
Mark Salyzyn95132e92013-11-22 10:55:48 -0800952 if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800953 dev = dev->next = new log_device_t("system", false);
Traian Schiau59763032015-04-10 15:51:39 +0300954 g_devCount++;
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800955 }
Mark Salyzyn99f47a92014-04-07 14:58:08 -0700956 if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800957 dev = dev->next = new log_device_t("crash", false);
Traian Schiau59763032015-04-10 15:51:39 +0300958 g_devCount++;
Mark Salyzyn99f47a92014-04-07 14:58:08 -0700959 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800960 }
961
Traian Schiau59763032015-04-10 15:51:39 +0300962 if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
963 logcat_panic(true, "-r requires -f as well\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800964 }
965
Traian Schiau59763032015-04-10 15:51:39 +0300966 setupOutput();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800967
968 if (hasSetLogFormat == 0) {
969 const char* logFormat = getenv("ANDROID_PRINTF_LOG");
970
971 if (logFormat != NULL) {
972 err = setLogFormat(logFormat);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800973 if (err < 0) {
Mark Salyzyn95132e92013-11-22 10:55:48 -0800974 fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800975 logFormat);
976 }
Mark Salyzyn649fc602014-09-16 09:15:15 -0700977 } else {
978 setLogFormat("threadtime");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800979 }
980 }
981
982 if (forceFilters) {
983 err = android_log_addFilterString(g_logformat, forceFilters);
984 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300985 logcat_panic(false, "Invalid filter expression in logcat args\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800986 }
987 } else if (argc == optind) {
988 // Add from environment variable
989 char *env_tags_orig = getenv("ANDROID_LOG_TAGS");
990
991 if (env_tags_orig != NULL) {
992 err = android_log_addFilterString(g_logformat, env_tags_orig);
993
Mark Salyzyn95132e92013-11-22 10:55:48 -0800994 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300995 logcat_panic(true,
996 "Invalid filter expression in ANDROID_LOG_TAGS\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800997 }
998 }
999 } else {
1000 // Add from commandline
1001 for (int i = optind ; i < argc ; i++) {
1002 err = android_log_addFilterString(g_logformat, argv[i]);
1003
Mark Salyzyn95132e92013-11-22 10:55:48 -08001004 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +03001005 logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001006 }
1007 }
1008 }
1009
Joe Onorato6fa09a02010-02-26 10:04:23 -08001010 dev = devices;
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001011 if (tail_time != log_time::EPOCH) {
Kristian Monsen562e5132015-06-05 14:10:12 -07001012 logger_list = android_logger_list_alloc_time(mode, tail_time, pid);
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001013 } else {
Kristian Monsen562e5132015-06-05 14:10:12 -07001014 logger_list = android_logger_list_alloc(mode, tail_lines, pid);
Mark Salyzynfa3716b2014-02-14 16:05:05 -08001015 }
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001016 const char *openDeviceFail = NULL;
1017 const char *clearFail = NULL;
1018 const char *setSizeFail = NULL;
1019 const char *getSizeFail = NULL;
1020 // We have three orthogonal actions below to clear, set log size and
1021 // get log size. All sharing the same iteration loop.
Joe Onorato6fa09a02010-02-26 10:04:23 -08001022 while (dev) {
Mark Salyzyn95132e92013-11-22 10:55:48 -08001023 dev->logger_list = logger_list;
1024 dev->logger = android_logger_open(logger_list,
1025 android_name_to_log_id(dev->device));
1026 if (!dev->logger) {
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001027 openDeviceFail = openDeviceFail ?: dev->device;
1028 dev = dev->next;
1029 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001030 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001031
1032 if (clearLog) {
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001033 if (android_logger_clear(dev->logger)) {
1034 clearFail = clearFail ?: dev->device;
Joe Onorato6fa09a02010-02-26 10:04:23 -08001035 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001036 }
1037
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001038 if (setLogSize) {
1039 if (android_logger_set_log_size(dev->logger, setLogSize)) {
1040 setSizeFail = setSizeFail ?: dev->device;
1041 }
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001042 }
1043
Joe Onorato6fa09a02010-02-26 10:04:23 -08001044 if (getLogSize) {
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001045 long size = android_logger_get_log_size(dev->logger);
1046 long readable = android_logger_get_log_readable_size(dev->logger);
Joe Onorato6fa09a02010-02-26 10:04:23 -08001047
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001048 if ((size < 0) || (readable < 0)) {
1049 getSizeFail = getSizeFail ?: dev->device;
1050 } else {
1051 printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
1052 "max entry is %db, max payload is %db\n", dev->device,
1053 value_of_size(size), multiplier_of_size(size),
1054 value_of_size(readable), multiplier_of_size(readable),
1055 (int) LOGGER_ENTRY_MAX_LEN,
1056 (int) LOGGER_ENTRY_MAX_PAYLOAD);
Joe Onorato6fa09a02010-02-26 10:04:23 -08001057 }
Joe Onorato6fa09a02010-02-26 10:04:23 -08001058 }
1059
1060 dev = dev->next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001061 }
Mark Salyzyn603b8e52015-09-16 15:34:00 -07001062 // report any errors in the above loop and exit
1063 if (openDeviceFail) {
1064 logcat_panic(false, "Unable to open log device '%s'\n", openDeviceFail);
1065 }
1066 if (clearFail) {
1067 logcat_panic(false, "failed to clear the '%s' log\n", clearFail);
1068 }
1069 if (setSizeFail) {
1070 logcat_panic(false, "failed to set the '%s' log size\n", setSizeFail);
1071 }
1072 if (getSizeFail) {
1073 logcat_panic(false, "failed to get the readable '%s' log size",
1074 getSizeFail);
1075 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001076
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001077 if (setPruneList) {
Traian Schiau59763032015-04-10 15:51:39 +03001078 size_t len = strlen(setPruneList);
1079 /*extra 32 bytes are needed by android_logger_set_prune_list */
1080 size_t bLen = len + 32;
1081 char *buf = NULL;
1082 if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
1083 buf[len] = '\0';
1084 if (android_logger_set_prune_list(logger_list, buf, bLen)) {
1085 logcat_panic(false, "failed to set the prune list");
1086 }
1087 free(buf);
1088 } else {
1089 logcat_panic(false, "failed to set the prune list (alloc)");
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001090 }
1091 }
1092
Mark Salyzyn1c950472014-04-01 17:19:47 -07001093 if (printStatistics || getPruneList) {
Mark Salyzyn34facab2014-02-06 14:48:50 -08001094 size_t len = 8192;
1095 char *buf;
1096
Mark Salyzyn083b0372015-12-04 10:59:45 -08001097 for (int retry = 32;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001098 (retry >= 0) && ((buf = new char [len]));
Traian Schiau59763032015-04-10 15:51:39 +03001099 delete [] buf, buf = NULL, --retry) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001100 if (getPruneList) {
1101 android_logger_get_prune_list(logger_list, buf, len);
1102 } else {
1103 android_logger_get_statistics(logger_list, buf, len);
1104 }
Mark Salyzyn34facab2014-02-06 14:48:50 -08001105 buf[len-1] = '\0';
Traian Schiau59763032015-04-10 15:51:39 +03001106 if (atol(buf) < 3) {
Mark Salyzyn34facab2014-02-06 14:48:50 -08001107 delete [] buf;
1108 buf = NULL;
1109 break;
1110 }
Traian Schiau59763032015-04-10 15:51:39 +03001111 size_t ret = atol(buf) + 1;
1112 if (ret <= len) {
1113 len = ret;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001114 break;
1115 }
Traian Schiau59763032015-04-10 15:51:39 +03001116 len = ret;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001117 }
1118
1119 if (!buf) {
Traian Schiau59763032015-04-10 15:51:39 +03001120 logcat_panic(false, "failed to read data");
Mark Salyzyn34facab2014-02-06 14:48:50 -08001121 }
1122
1123 // remove trailing FF
1124 char *cp = buf + len - 1;
1125 *cp = '\0';
1126 bool truncated = *--cp != '\f';
1127 if (!truncated) {
1128 *cp = '\0';
1129 }
1130
1131 // squash out the byte count
1132 cp = buf;
1133 if (!truncated) {
Mark Salyzyn22e287d2014-03-21 13:12:16 -07001134 while (isdigit(*cp)) {
1135 ++cp;
1136 }
1137 if (*cp == '\n') {
Mark Salyzyn34facab2014-02-06 14:48:50 -08001138 ++cp;
1139 }
1140 }
1141
1142 printf("%s", cp);
1143 delete [] buf;
Traian Schiau59763032015-04-10 15:51:39 +03001144 return EXIT_SUCCESS;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001145 }
1146
1147
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001148 if (getLogSize) {
Traian Schiau59763032015-04-10 15:51:39 +03001149 return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001150 }
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001151 if (setLogSize || setPruneList) {
Traian Schiau59763032015-04-10 15:51:39 +03001152 return EXIT_SUCCESS;
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001153 }
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -08001154 if (clearLog) {
Traian Schiau59763032015-04-10 15:51:39 +03001155 return EXIT_SUCCESS;
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -08001156 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001157
1158 //LOG_EVENT_INT(10, 12345);
1159 //LOG_EVENT_LONG(11, 0x1122334455667788LL);
1160 //LOG_EVENT_STRING(0, "whassup, doc?");
1161
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001162 dev = NULL;
Mark Salyzyn5f6738a2015-02-27 13:41:34 -08001163 log_device_t unexpected("unexpected", false);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001164 while (1) {
1165 struct log_msg log_msg;
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001166 log_device_t* d;
Mark Salyzyn95132e92013-11-22 10:55:48 -08001167 int ret = android_logger_list_read(logger_list, &log_msg);
1168
1169 if (ret == 0) {
Traian Schiau59763032015-04-10 15:51:39 +03001170 logcat_panic(false, "read: unexpected EOF!\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001171 }
1172
1173 if (ret < 0) {
1174 if (ret == -EAGAIN) {
1175 break;
1176 }
1177
1178 if (ret == -EIO) {
Traian Schiau59763032015-04-10 15:51:39 +03001179 logcat_panic(false, "read: unexpected EOF!\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001180 }
1181 if (ret == -EINVAL) {
Traian Schiau59763032015-04-10 15:51:39 +03001182 logcat_panic(false, "read: unexpected length.\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001183 }
Traian Schiau59763032015-04-10 15:51:39 +03001184 logcat_panic(false, "logcat read failure");
Mark Salyzyn95132e92013-11-22 10:55:48 -08001185 }
1186
Mark Salyzyn083b0372015-12-04 10:59:45 -08001187 for (d = devices; d; d = d->next) {
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001188 if (android_name_to_log_id(d->device) == log_msg.id()) {
Mark Salyzyn95132e92013-11-22 10:55:48 -08001189 break;
1190 }
1191 }
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001192 if (!d) {
Traian Schiau59763032015-04-10 15:51:39 +03001193 g_devCount = 2; // set to Multiple
Mark Salyzyn9421b0c2015-02-26 14:33:35 -08001194 d = &unexpected;
1195 d->binary = log_msg.id() == LOG_ID_EVENTS;
Mark Salyzyn95132e92013-11-22 10:55:48 -08001196 }
1197
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001198 if (dev != d) {
1199 dev = d;
Traian Schiau59763032015-04-10 15:51:39 +03001200 maybePrintStart(dev, printDividers);
Mark Salyzyn7b30ff82015-01-26 13:41:33 -08001201 }
Traian Schiau59763032015-04-10 15:51:39 +03001202 if (g_printBinary) {
1203 printBinary(&log_msg);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001204 } else {
Traian Schiau59763032015-04-10 15:51:39 +03001205 processBuffer(dev, &log_msg);
Mark Salyzyn95132e92013-11-22 10:55:48 -08001206 }
1207 }
1208
1209 android_logger_list_free(logger_list);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001210
Traian Schiau59763032015-04-10 15:51:39 +03001211 return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001212}