blob: 736e02eaa94c3ede9dfe30c323bc6c7c31a2eccb [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>
Aristidis Papaioannoueba73442014-10-16 22:19:55 -07009#include <math.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070010#include <sched.h>
11#include <signal.h>
12#include <stdarg.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080013#include <stdio.h>
14#include <stdlib.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080015#include <string.h>
Traian Schiau59763032015-04-10 15:51:39 +030016#include <sys/cdefs.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080017#include <sys/socket.h>
18#include <sys/stat.h>
Mark Salyzynf3555d92015-05-27 07:39:56 -070019#include <sys/types.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070020#include <time.h>
21#include <unistd.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080022
Mark Salyzynf3555d92015-05-27 07:39:56 -070023#include <memory>
24#include <string>
25
26#include <base/file.h>
27#include <base/strings.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070028#include <cutils/sched_policy.h>
Mark Salyzyn65772ca2013-12-13 11:10:11 -080029#include <cutils/sockets.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070030#include <log/event_tag_map.h>
Mark Salyzyn95132e92013-11-22 10:55:48 -080031#include <log/log.h>
Mark Salyzynfa3716b2014-02-14 16:05:05 -080032#include <log/log_read.h>
Colin Cross9227bd32013-07-23 16:59:20 -070033#include <log/logd.h>
Mark Salyzyn3ef730c2015-06-02 07:57:16 -070034#include <log/logger.h>
Colin Cross9227bd32013-07-23 16:59:20 -070035#include <log/logprint.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080037#define DEFAULT_MAX_ROTATED_LOGS 4
38
39static AndroidLogFormat * g_logformat;
40
41/* logd prefixes records with a length field */
42#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
43
Joe Onorato6fa09a02010-02-26 10:04:23 -080044struct log_device_t {
Mark Salyzyn95132e92013-11-22 10:55:48 -080045 const char* device;
Joe Onorato6fa09a02010-02-26 10:04:23 -080046 bool binary;
Mark Salyzyn95132e92013-11-22 10:55:48 -080047 struct logger *logger;
48 struct logger_list *logger_list;
Joe Onorato6fa09a02010-02-26 10:04:23 -080049 bool printed;
Joe Onorato6fa09a02010-02-26 10:04:23 -080050
Joe Onorato6fa09a02010-02-26 10:04:23 -080051 log_device_t* next;
52
Mark Salyzyn5f6738a2015-02-27 13:41:34 -080053 log_device_t(const char* d, bool b) {
Joe Onorato6fa09a02010-02-26 10:04:23 -080054 device = d;
55 binary = b;
Joe Onorato6fa09a02010-02-26 10:04:23 -080056 next = NULL;
57 printed = false;
Traian Schiau59763032015-04-10 15:51:39 +030058 logger = NULL;
59 logger_list = NULL;
Joe Onorato6fa09a02010-02-26 10:04:23 -080060 }
Joe Onorato6fa09a02010-02-26 10:04:23 -080061};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080062
63namespace android {
64
65/* Global Variables */
66
67static const char * g_outputFileName = NULL;
Traian Schiau59763032015-04-10 15:51:39 +030068// 0 means "no log rotation"
69static size_t g_logRotateSizeKBytes = 0;
70// 0 means "unbounded"
71static size_t g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080072static int g_outFD = -1;
Traian Schiau59763032015-04-10 15:51:39 +030073static size_t g_outByteCount = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080074static int g_printBinary = 0;
Mark Salyzyn9421b0c2015-02-26 14:33:35 -080075static int g_devCount = 0; // >1 means multiple
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080076
Traian Schiau59763032015-04-10 15:51:39 +030077__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
78
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080079static int openLogFile (const char *pathname)
80{
Edwin Vane80b221c2012-08-13 12:55:07 -040081 return open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080082}
83
84static void rotateLogs()
85{
86 int err;
87
88 // Can't rotate logs if we're not outputting to a file
89 if (g_outputFileName == NULL) {
90 return;
91 }
92
93 close(g_outFD);
94
Aristidis Papaioannoueba73442014-10-16 22:19:55 -070095 // Compute the maximum number of digits needed to count up to g_maxRotatedLogs in decimal.
96 // eg: g_maxRotatedLogs == 30 -> log10(30) == 1.477 -> maxRotationCountDigits == 2
97 int maxRotationCountDigits =
98 (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
99
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800100 for (int i = g_maxRotatedLogs ; i > 0 ; i--) {
101 char *file0, *file1;
102
Aristidis Papaioannoueba73442014-10-16 22:19:55 -0700103 asprintf(&file1, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800104
105 if (i - 1 == 0) {
106 asprintf(&file0, "%s", g_outputFileName);
107 } else {
Aristidis Papaioannoueba73442014-10-16 22:19:55 -0700108 asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800109 }
110
Traian Schiau59763032015-04-10 15:51:39 +0300111 if (!file0 || !file1) {
112 perror("while rotating log files");
113 break;
114 }
115
116 err = rename(file0, file1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800117
118 if (err < 0 && errno != ENOENT) {
119 perror("while rotating log files");
120 }
121
122 free(file1);
123 free(file0);
124 }
125
Traian Schiau59763032015-04-10 15:51:39 +0300126 g_outFD = openLogFile(g_outputFileName);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800127
128 if (g_outFD < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300129 logcat_panic(false, "couldn't open output file");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800130 }
131
132 g_outByteCount = 0;
133
134}
135
Mark Salyzyn95132e92013-11-22 10:55:48 -0800136void printBinary(struct log_msg *buf)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800137{
Mark Salyzyn95132e92013-11-22 10:55:48 -0800138 size_t size = buf->len();
139
140 TEMP_FAILURE_RETRY(write(g_outFD, buf, size));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800141}
142
Mark Salyzyn95132e92013-11-22 10:55:48 -0800143static void processBuffer(log_device_t* dev, struct log_msg *buf)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800144{
Mathias Agopian50844522010-03-17 16:10:26 -0700145 int bytesWritten = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800146 int err;
147 AndroidLogEntry entry;
148 char binaryMsgBuf[1024];
149
Joe Onorato6fa09a02010-02-26 10:04:23 -0800150 if (dev->binary) {
Mark Salyzyn9421b0c2015-02-26 14:33:35 -0800151 static bool hasOpenedEventTagMap = false;
152 static EventTagMap *eventTagMap = NULL;
153
154 if (!eventTagMap && !hasOpenedEventTagMap) {
155 eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
156 hasOpenedEventTagMap = true;
157 }
Mark Salyzyn95132e92013-11-22 10:55:48 -0800158 err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
Mark Salyzyn9421b0c2015-02-26 14:33:35 -0800159 eventTagMap,
Mark Salyzyn95132e92013-11-22 10:55:48 -0800160 binaryMsgBuf,
161 sizeof(binaryMsgBuf));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800162 //printf(">>> pri=%d len=%d msg='%s'\n",
163 // entry.priority, entry.messageLen, entry.message);
164 } else {
Mark Salyzyn95132e92013-11-22 10:55:48 -0800165 err = android_log_processLogBuffer(&buf->entry_v1, &entry);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800166 }
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800167 if (err < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800168 goto error;
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800169 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800170
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800171 if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800172 bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
173
174 if (bytesWritten < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300175 logcat_panic(false, "output error");
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800176 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800177 }
178
179 g_outByteCount += bytesWritten;
180
Mark Salyzyn95132e92013-11-22 10:55:48 -0800181 if (g_logRotateSizeKBytes > 0
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800182 && (g_outByteCount / 1024) >= g_logRotateSizeKBytes
183 ) {
184 rotateLogs();
185 }
186
187error:
188 //fprintf (stderr, "Error processing record\n");
189 return;
190}
191
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800192static void maybePrintStart(log_device_t* dev, bool printDividers) {
193 if (!dev->printed || printDividers) {
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800194 if (g_devCount > 1 && !g_printBinary) {
195 char buf[1024];
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800196 snprintf(buf, sizeof(buf), "--------- %s %s\n",
197 dev->printed ? "switch to" : "beginning of",
Mark Salyzyn95132e92013-11-22 10:55:48 -0800198 dev->device);
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800199 if (write(g_outFD, buf, strlen(buf)) < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300200 logcat_panic(false, "output error");
Joe Onorato6fa09a02010-02-26 10:04:23 -0800201 }
202 }
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800203 dev->printed = true;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800204 }
205}
206
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800207static void setupOutput()
208{
209
210 if (g_outputFileName == NULL) {
211 g_outFD = STDOUT_FILENO;
212
213 } else {
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700214 if (set_sched_policy(0, SP_BACKGROUND) < 0) {
215 fprintf(stderr, "failed to set background scheduling policy\n");
216 }
217
218 struct sched_param param;
219 memset(&param, 0, sizeof(param));
220 if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
221 fprintf(stderr, "failed to set to batch scheduler\n");
222 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800223
224 g_outFD = openLogFile (g_outputFileName);
225
226 if (g_outFD < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300227 logcat_panic(false, "couldn't open output file");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800228 }
229
Mark Salyzyn3ef730c2015-06-02 07:57:16 -0700230 struct stat statbuf;
Traian Schiau59763032015-04-10 15:51:39 +0300231 if (fstat(g_outFD, &statbuf) == -1) {
232 close(g_outFD);
233 logcat_panic(false, "couldn't get output file stat\n");
234 }
235
236 if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
237 close(g_outFD);
238 logcat_panic(false, "invalid output file stat\n");
239 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800240
241 g_outByteCount = statbuf.st_size;
242 }
243}
244
245static void show_help(const char *cmd)
246{
247 fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
248
249 fprintf(stderr, "options include:\n"
250 " -s Set default filter to silent.\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700251 " Like specifying filterspec '*:S'\n"
Mark Salyzynf3555d92015-05-27 07:39:56 -0700252 " -f <filename> Log to file. Default is stdout\n"
Traian Schiau59763032015-04-10 15:51:39 +0300253 " -r <kbytes> Rotate log every kbytes. Requires -f\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800254 " -n <count> Sets max number of rotated logs to <count>, default 4\n"
Pierre Zurekead88fc2010-10-17 22:39:37 +0200255 " -v <format> Sets the log print format, where <format> is:\n\n"
Mark Salyzynb932b2f2015-05-15 09:01:58 -0700256 " brief color long printable process raw tag thread\n"
257 " threadtime time usec\n\n"
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800258 " -D print dividers between each log buffer\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800259 " -c clear (flush) the entire log and exit\n"
260 " -d dump the log and then exit (don't block)\n"
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800261 " -t <count> print only the most recent <count> lines (implies -d)\n"
Mark Salyzyn190b7ac2014-09-01 10:41:33 -0700262 " -t '<time>' print most recent lines since specified time (implies -d)\n"
Mark Salyzyn5d3d1f12013-12-09 13:47:00 -0800263 " -T <count> print only the most recent <count> lines (does not imply -d)\n"
Mark Salyzyn190b7ac2014-09-01 10:41:33 -0700264 " -T '<time>' print most recent lines since specified time (not imply -d)\n"
265 " count is pure numerical, time is 'MM-DD hh:mm:ss.mmm'\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800266 " -g get the size of the log's ring buffer and exit\n"
Mark Salyzyn7c975ac2014-12-15 10:01:31 -0800267 " -L dump logs from prior to last reboot\n"
Mark Salyzyn34facab2014-02-06 14:48:50 -0800268 " -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio',\n"
Mark Salyzyn99f47a92014-04-07 14:58:08 -0700269 " 'events', 'crash' or 'all'. Multiple -b parameters are\n"
270 " allowed and results are interleaved. The default is\n"
271 " -b main -b system -b crash.\n"
Mark Salyzyn34facab2014-02-06 14:48:50 -0800272 " -B output the log in binary.\n"
Mark Salyzynbbbe14f2014-04-11 13:49:43 -0700273 " -S output statistics.\n"
274 " -G <size> set size of log ring buffer, may suffix with K or M.\n"
275 " -p print prune white and ~black list. Service is specified as\n"
276 " UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
277 " with ~, otherwise weighed for longevity if unadorned. All\n"
278 " other pruning activity is oldest first. Special case ~!\n"
279 " represents an automatic quicker pruning for the noisiest\n"
280 " UID as determined by the current statistics.\n"
281 " -P '<list> ...' set prune white and ~black list, using same format as\n"
282 " printed above. Must be quoted.\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800283
284 fprintf(stderr,"\nfilterspecs are a series of \n"
285 " <tag>[:priority]\n\n"
286 "where <tag> is a log component tag (or * for all) and priority is:\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700287 " V Verbose (default for <tag>)\n"
288 " D Debug (default for '*')\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800289 " I Info\n"
290 " W Warn\n"
291 " E Error\n"
292 " F Fatal\n"
Mark Salyzynbba894a2015-03-09 09:32:56 -0700293 " S Silent (suppress all output)\n"
294 "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
295 "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
296 "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
297 "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
298 "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
Mark Salyzyn649fc602014-09-16 09:15:15 -0700299 "or defaults to \"threadtime\"\n\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800300}
301
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800302static int setLogFormat(const char * formatString)
303{
304 static AndroidLogPrintFormat format;
305
306 format = android_log_formatFromString(formatString);
307
308 if (format == FORMAT_OFF) {
309 // FORMAT_OFF means invalid string
310 return -1;
311 }
312
Mark Salyzyne1f20042015-05-06 08:40:40 -0700313 return android_log_setPrintFormat(g_logformat, format);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800314}
315
Mark Salyzyn671e3432014-05-06 07:34:59 -0700316static const char multipliers[][2] = {
317 { "" },
318 { "K" },
319 { "M" },
320 { "G" }
321};
322
323static unsigned long value_of_size(unsigned long value)
324{
325 for (unsigned i = 0;
326 (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
327 value /= 1024, ++i) ;
328 return value;
329}
330
331static const char *multiplier_of_size(unsigned long value)
332{
333 unsigned i;
334 for (i = 0;
335 (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
336 value /= 1024, ++i) ;
337 return multipliers[i];
338}
339
Traian Schiau59763032015-04-10 15:51:39 +0300340/*String to unsigned int, returns -1 if it fails*/
341static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0,
342 size_t max = SIZE_MAX)
343{
344 char *endp;
345 errno = 0;
346 size_t ret = (size_t) strtoll(ptr, &endp, 0);
347
348 if (endp[0] != '\0' || errno != 0 ) {
349 return false;
350 }
351
352 if (ret > max || ret < min) {
353 return false;
354 }
355
356 *val = ret;
357 return true;
358}
359
360static void logcat_panic(bool showHelp, const char *fmt, ...)
361{
Mark Salyzyn77d7e812015-04-13 09:27:57 -0700362 va_list args;
363 va_start(args, fmt);
364 vfprintf(stderr, fmt, args);
365 va_end(args);
Traian Schiau59763032015-04-10 15:51:39 +0300366
367 if (showHelp) {
368 show_help(getprogname());
369 }
370
371 exit(EXIT_FAILURE);
372}
373
Mark Salyzynf3555d92015-05-27 07:39:56 -0700374static const char g_defaultTimeFormat[] = "%m-%d %H:%M:%S.%q";
375
376// Find last logged line in gestalt of all matching existing output files
377static log_time lastLogTime(char *outputFileName) {
378 log_time retval(log_time::EPOCH);
379 if (!outputFileName) {
380 return retval;
381 }
382
383 log_time now(CLOCK_REALTIME);
384
385 std::string directory;
386 char *file = strrchr(outputFileName, '/');
387 if (!file) {
388 directory = ".";
389 file = outputFileName;
390 } else {
391 *file = '\0';
392 directory = outputFileName;
393 *file = '/';
394 ++file;
395 }
396 size_t len = strlen(file);
397 log_time modulo(0, NS_PER_SEC);
398 std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(directory.c_str()), closedir);
399 struct dirent *dp;
400 while ((dp = readdir(dir.get())) != NULL) {
401 if ((dp->d_type != DT_REG)
402 || strncmp(dp->d_name, file, len)
403 || (dp->d_name[len]
404 && ((dp->d_name[len] != '.')
405 || !isdigit(dp->d_name[len+1])))) {
406 continue;
407 }
408
409 std::string file_name = directory;
410 file_name += "/";
411 file_name += dp->d_name;
412 std::string file;
413 if (!android::base::ReadFileToString(file_name, &file)) {
414 continue;
415 }
416
417 bool found = false;
418 for (const auto& line : android::base::Split(file, "\n")) {
419 log_time t(log_time::EPOCH);
420 char *ep = t.strptime(line.c_str(), g_defaultTimeFormat);
421 if (!ep || (*ep != ' ')) {
422 continue;
423 }
424 // determine the time precision of the logs (eg: msec or usec)
425 for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
426 if (t.tv_nsec % (mod * 10)) {
427 modulo.tv_nsec = mod;
428 break;
429 }
430 }
431 // We filter any times later than current as we may not have the
432 // year stored with each log entry. Also, since it is possible for
433 // entries to be recorded out of order (very rare) we select the
434 // maximum we find just in case.
435 if ((t < now) && (t > retval)) {
436 retval = t;
437 found = true;
438 }
439 }
440 // We count on the basename file to be the definitive end, so stop here.
441 if (!dp->d_name[len] && found) {
442 break;
443 }
444 }
445 if (retval == log_time::EPOCH) {
446 return retval;
447 }
448 // tail_time prints matching or higher, round up by the modulo to prevent
449 // a replay of the last entry we have just checked.
450 retval += modulo;
451 return retval;
452}
453
Traian Schiau59763032015-04-10 15:51:39 +0300454} /* namespace android */
455
456
Joe Onorato6fa09a02010-02-26 10:04:23 -0800457int main(int argc, char **argv)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800458{
Traian Schiau59763032015-04-10 15:51:39 +0300459 using namespace android;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800460 int err;
461 int hasSetLogFormat = 0;
462 int clearLog = 0;
463 int getLogSize = 0;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800464 unsigned long setLogSize = 0;
465 int getPruneList = 0;
466 char *setPruneList = NULL;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800467 int printStatistics = 0;
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800468 int mode = ANDROID_LOG_RDONLY;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800469 const char *forceFilters = NULL;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800470 log_device_t* devices = NULL;
471 log_device_t* dev;
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800472 bool printDividers = false;
Mark Salyzyn95132e92013-11-22 10:55:48 -0800473 struct logger_list *logger_list;
Traian Schiau59763032015-04-10 15:51:39 +0300474 size_t tail_lines = 0;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800475 log_time tail_time(log_time::EPOCH);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800476
Mark Salyzyn65772ca2013-12-13 11:10:11 -0800477 signal(SIGPIPE, exit);
478
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800479 g_logformat = android_log_format_new();
480
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800481 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
Traian Schiau59763032015-04-10 15:51:39 +0300482 show_help(argv[0]);
483 return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800484 }
485
486 for (;;) {
487 int ret;
488
Traian Schiau59763032015-04-10 15:51:39 +0300489 ret = getopt(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800490
491 if (ret < 0) {
492 break;
493 }
494
495 switch(ret) {
Mark Salyzyn95132e92013-11-22 10:55:48 -0800496 case 's':
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800497 // default to all silent
498 android_log_addFilterRule(g_logformat, "*:s");
499 break;
500
501 case 'c':
502 clearLog = 1;
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800503 mode |= ANDROID_LOG_WRONLY;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800504 break;
505
Mark Salyzyn7c975ac2014-12-15 10:01:31 -0800506 case 'L':
507 mode |= ANDROID_LOG_PSTORE;
508 break;
509
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800510 case 'd':
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800511 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800512 break;
513
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800514 case 't':
Mark Salyzyn2d3f38a2015-01-26 10:46:44 -0800515 mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
Mark Salyzyn5d3d1f12013-12-09 13:47:00 -0800516 /* FALLTHRU */
517 case 'T':
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800518 if (strspn(optarg, "0123456789") != strlen(optarg)) {
Mark Salyzynf3555d92015-05-27 07:39:56 -0700519 char *cp = tail_time.strptime(optarg, g_defaultTimeFormat);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800520 if (!cp) {
Traian Schiau59763032015-04-10 15:51:39 +0300521 logcat_panic(false,
522 "-%c \"%s\" not in \"%s\" time format\n",
Mark Salyzynf3555d92015-05-27 07:39:56 -0700523 ret, optarg, g_defaultTimeFormat);
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800524 }
525 if (*cp) {
526 char c = *cp;
527 *cp = '\0';
528 fprintf(stderr,
529 "WARNING: -%c \"%s\"\"%c%s\" time truncated\n",
530 ret, optarg, c, cp + 1);
531 *cp = c;
532 }
533 } else {
Traian Schiau59763032015-04-10 15:51:39 +0300534 if (!getSizeTArg(optarg, &tail_lines, 1)) {
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800535 fprintf(stderr,
536 "WARNING: -%c %s invalid, setting to 1\n",
537 ret, optarg);
538 tail_lines = 1;
539 }
540 }
Dan Egnord1d3b6d2010-03-11 20:32:17 -0800541 break;
542
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800543 case 'D':
544 printDividers = true;
545 break;
546
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800547 case 'g':
548 getLogSize = 1;
549 break;
550
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800551 case 'G': {
Traian Schiau59763032015-04-10 15:51:39 +0300552 char *cp;
553 if (strtoll(optarg, &cp, 0) > 0) {
554 setLogSize = strtoll(optarg, &cp, 0);
555 } else {
556 setLogSize = 0;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800557 }
558
559 switch(*cp) {
560 case 'g':
561 case 'G':
562 setLogSize *= 1024;
563 /* FALLTHRU */
564 case 'm':
565 case 'M':
566 setLogSize *= 1024;
567 /* FALLTHRU */
568 case 'k':
569 case 'K':
570 setLogSize *= 1024;
571 /* FALLTHRU */
572 case '\0':
573 break;
574
575 default:
576 setLogSize = 0;
577 }
578
579 if (!setLogSize) {
580 fprintf(stderr, "ERROR: -G <num><multiplier>\n");
Traian Schiau59763032015-04-10 15:51:39 +0300581 return EXIT_FAILURE;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800582 }
583 }
584 break;
585
586 case 'p':
587 getPruneList = 1;
588 break;
589
590 case 'P':
591 setPruneList = optarg;
592 break;
593
Joe Onorato6fa09a02010-02-26 10:04:23 -0800594 case 'b': {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800595 if (strcmp(optarg, "all") == 0) {
596 while (devices) {
597 dev = devices;
598 devices = dev->next;
599 delete dev;
600 }
601
Mark Salyzynd0bd1b12014-10-10 15:25:38 -0700602 devices = dev = NULL;
Traian Schiau59763032015-04-10 15:51:39 +0300603 g_devCount = 0;
Mark Salyzynd0bd1b12014-10-10 15:25:38 -0700604 for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
605 const char *name = android_log_id_to_name((log_id_t)i);
606 log_id_t log_id = android_name_to_log_id(name);
607
608 if (log_id != (log_id_t)i) {
609 continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800610 }
Mark Salyzynd0bd1b12014-10-10 15:25:38 -0700611
612 bool binary = strcmp(name, "events") == 0;
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800613 log_device_t* d = new log_device_t(name, binary);
Mark Salyzynd0bd1b12014-10-10 15:25:38 -0700614
615 if (dev) {
616 dev->next = d;
617 dev = d;
618 } else {
619 devices = dev = d;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800620 }
Traian Schiau59763032015-04-10 15:51:39 +0300621 g_devCount++;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800622 }
623 break;
624 }
625
Joe Onorato6fa09a02010-02-26 10:04:23 -0800626 bool binary = strcmp(optarg, "events") == 0;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800627
628 if (devices) {
629 dev = devices;
630 while (dev->next) {
631 dev = dev->next;
632 }
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800633 dev->next = new log_device_t(optarg, binary);
Joe Onorato6fa09a02010-02-26 10:04:23 -0800634 } else {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800635 devices = new log_device_t(optarg, binary);
Joe Onorato6fa09a02010-02-26 10:04:23 -0800636 }
Traian Schiau59763032015-04-10 15:51:39 +0300637 g_devCount++;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800638 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800639 break;
640
641 case 'B':
Traian Schiau59763032015-04-10 15:51:39 +0300642 g_printBinary = 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800643 break;
644
645 case 'f':
Mark Salyzynf3555d92015-05-27 07:39:56 -0700646 if ((tail_time == log_time::EPOCH) && (tail_lines != 0)) {
647 tail_time = lastLogTime(optarg);
648 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800649 // redirect output to a file
Traian Schiau59763032015-04-10 15:51:39 +0300650 g_outputFileName = optarg;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800651 break;
652
653 case 'r':
Traian Schiau59763032015-04-10 15:51:39 +0300654 if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
655 logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800656 }
657 break;
658
659 case 'n':
Traian Schiau59763032015-04-10 15:51:39 +0300660 if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
661 logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800662 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800663 break;
664
665 case 'v':
666 err = setLogFormat (optarg);
667 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300668 logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800669 }
Mark Salyzyne1f20042015-05-06 08:40:40 -0700670 hasSetLogFormat |= err;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800671 break;
672
673 case 'Q':
674 /* this is a *hidden* option used to start a version of logcat */
675 /* in an emulated device only. it basically looks for androidboot.logcat= */
676 /* on the kernel command line. If something is found, it extracts a log filter */
677 /* and uses it to run the program. If nothing is found, the program should */
678 /* quit immediately */
679#define KERNEL_OPTION "androidboot.logcat="
680#define CONSOLE_OPTION "androidboot.console="
681 {
682 int fd;
683 char* logcat;
684 char* console;
685 int force_exit = 1;
686 static char cmdline[1024];
687
688 fd = open("/proc/cmdline", O_RDONLY);
689 if (fd >= 0) {
690 int n = read(fd, cmdline, sizeof(cmdline)-1 );
691 if (n < 0) n = 0;
692 cmdline[n] = 0;
693 close(fd);
694 } else {
695 cmdline[0] = 0;
696 }
697
698 logcat = strstr( cmdline, KERNEL_OPTION );
699 console = strstr( cmdline, CONSOLE_OPTION );
700 if (logcat != NULL) {
701 char* p = logcat + sizeof(KERNEL_OPTION)-1;;
702 char* q = strpbrk( p, " \t\n\r" );;
703
704 if (q != NULL)
705 *q = 0;
706
707 forceFilters = p;
708 force_exit = 0;
709 }
710 /* if nothing found or invalid filters, exit quietly */
Traian Schiau59763032015-04-10 15:51:39 +0300711 if (force_exit) {
712 return EXIT_SUCCESS;
713 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800714
715 /* redirect our output to the emulator console */
716 if (console) {
717 char* p = console + sizeof(CONSOLE_OPTION)-1;
718 char* q = strpbrk( p, " \t\n\r" );
719 char devname[64];
720 int len;
721
722 if (q != NULL) {
723 len = q - p;
724 } else
725 len = strlen(p);
726
727 len = snprintf( devname, sizeof(devname), "/dev/%.*s", len, p );
728 fprintf(stderr, "logcat using %s (%d)\n", devname, len);
729 if (len < (int)sizeof(devname)) {
730 fd = open( devname, O_WRONLY );
731 if (fd >= 0) {
732 dup2(fd, 1);
733 dup2(fd, 2);
734 close(fd);
735 }
736 }
737 }
738 }
739 break;
740
Mark Salyzyn34facab2014-02-06 14:48:50 -0800741 case 'S':
742 printStatistics = 1;
743 break;
744
Traian Schiau59763032015-04-10 15:51:39 +0300745 case ':':
746 logcat_panic(true, "Option -%c needs an argument\n", optopt);
747 break;
748
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800749 default:
Traian Schiau59763032015-04-10 15:51:39 +0300750 logcat_panic(true, "Unrecognized Option %c\n", optopt);
751 break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800752 }
753 }
754
Joe Onorato6fa09a02010-02-26 10:04:23 -0800755 if (!devices) {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800756 dev = devices = new log_device_t("main", false);
Traian Schiau59763032015-04-10 15:51:39 +0300757 g_devCount = 1;
Mark Salyzyn95132e92013-11-22 10:55:48 -0800758 if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800759 dev = dev->next = new log_device_t("system", false);
Traian Schiau59763032015-04-10 15:51:39 +0300760 g_devCount++;
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800761 }
Mark Salyzyn99f47a92014-04-07 14:58:08 -0700762 if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800763 dev = dev->next = new log_device_t("crash", false);
Traian Schiau59763032015-04-10 15:51:39 +0300764 g_devCount++;
Mark Salyzyn99f47a92014-04-07 14:58:08 -0700765 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800766 }
767
Traian Schiau59763032015-04-10 15:51:39 +0300768 if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
769 logcat_panic(true, "-r requires -f as well\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800770 }
771
Traian Schiau59763032015-04-10 15:51:39 +0300772 setupOutput();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800773
774 if (hasSetLogFormat == 0) {
775 const char* logFormat = getenv("ANDROID_PRINTF_LOG");
776
777 if (logFormat != NULL) {
778 err = setLogFormat(logFormat);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800779 if (err < 0) {
Mark Salyzyn95132e92013-11-22 10:55:48 -0800780 fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800781 logFormat);
782 }
Mark Salyzyn649fc602014-09-16 09:15:15 -0700783 } else {
784 setLogFormat("threadtime");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800785 }
786 }
787
788 if (forceFilters) {
789 err = android_log_addFilterString(g_logformat, forceFilters);
790 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300791 logcat_panic(false, "Invalid filter expression in logcat args\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800792 }
793 } else if (argc == optind) {
794 // Add from environment variable
795 char *env_tags_orig = getenv("ANDROID_LOG_TAGS");
796
797 if (env_tags_orig != NULL) {
798 err = android_log_addFilterString(g_logformat, env_tags_orig);
799
Mark Salyzyn95132e92013-11-22 10:55:48 -0800800 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300801 logcat_panic(true,
802 "Invalid filter expression in ANDROID_LOG_TAGS\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800803 }
804 }
805 } else {
806 // Add from commandline
807 for (int i = optind ; i < argc ; i++) {
808 err = android_log_addFilterString(g_logformat, argv[i]);
809
Mark Salyzyn95132e92013-11-22 10:55:48 -0800810 if (err < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300811 logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800812 }
813 }
814 }
815
Joe Onorato6fa09a02010-02-26 10:04:23 -0800816 dev = devices;
Mark Salyzynfa3716b2014-02-14 16:05:05 -0800817 if (tail_time != log_time::EPOCH) {
818 logger_list = android_logger_list_alloc_time(mode, tail_time, 0);
819 } else {
820 logger_list = android_logger_list_alloc(mode, tail_lines, 0);
821 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800822 while (dev) {
Mark Salyzyn95132e92013-11-22 10:55:48 -0800823 dev->logger_list = logger_list;
824 dev->logger = android_logger_open(logger_list,
825 android_name_to_log_id(dev->device));
826 if (!dev->logger) {
Traian Schiau59763032015-04-10 15:51:39 +0300827 logcat_panic(false, "Unable to open log device '%s'\n",
828 dev->device);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800829 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800830
831 if (clearLog) {
832 int ret;
Mark Salyzyn95132e92013-11-22 10:55:48 -0800833 ret = android_logger_clear(dev->logger);
Joe Onorato6fa09a02010-02-26 10:04:23 -0800834 if (ret) {
Traian Schiau59763032015-04-10 15:51:39 +0300835 logcat_panic(false, "failed to clear the log");
Joe Onorato6fa09a02010-02-26 10:04:23 -0800836 }
Joe Onorato6fa09a02010-02-26 10:04:23 -0800837 }
838
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800839 if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
Traian Schiau59763032015-04-10 15:51:39 +0300840 logcat_panic(false, "failed to set the log size");
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800841 }
842
Joe Onorato6fa09a02010-02-26 10:04:23 -0800843 if (getLogSize) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800844 long size, readable;
Joe Onorato6fa09a02010-02-26 10:04:23 -0800845
Mark Salyzyn95132e92013-11-22 10:55:48 -0800846 size = android_logger_get_log_size(dev->logger);
Joe Onorato6fa09a02010-02-26 10:04:23 -0800847 if (size < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300848 logcat_panic(false, "failed to get the log size");
Joe Onorato6fa09a02010-02-26 10:04:23 -0800849 }
850
Mark Salyzyn95132e92013-11-22 10:55:48 -0800851 readable = android_logger_get_log_readable_size(dev->logger);
Joe Onorato6fa09a02010-02-26 10:04:23 -0800852 if (readable < 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300853 logcat_panic(false, "failed to get the readable log size");
Joe Onorato6fa09a02010-02-26 10:04:23 -0800854 }
855
Mark Salyzyn671e3432014-05-06 07:34:59 -0700856 printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
Joe Onorato6fa09a02010-02-26 10:04:23 -0800857 "max entry is %db, max payload is %db\n", dev->device,
Mark Salyzyn671e3432014-05-06 07:34:59 -0700858 value_of_size(size), multiplier_of_size(size),
859 value_of_size(readable), multiplier_of_size(readable),
Joe Onorato6fa09a02010-02-26 10:04:23 -0800860 (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
861 }
862
863 dev = dev->next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800864 }
865
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800866 if (setPruneList) {
Traian Schiau59763032015-04-10 15:51:39 +0300867 size_t len = strlen(setPruneList);
868 /*extra 32 bytes are needed by android_logger_set_prune_list */
869 size_t bLen = len + 32;
870 char *buf = NULL;
871 if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
872 buf[len] = '\0';
873 if (android_logger_set_prune_list(logger_list, buf, bLen)) {
874 logcat_panic(false, "failed to set the prune list");
875 }
876 free(buf);
877 } else {
878 logcat_panic(false, "failed to set the prune list (alloc)");
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800879 }
880 }
881
Mark Salyzyn1c950472014-04-01 17:19:47 -0700882 if (printStatistics || getPruneList) {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800883 size_t len = 8192;
884 char *buf;
885
886 for(int retry = 32;
887 (retry >= 0) && ((buf = new char [len]));
Traian Schiau59763032015-04-10 15:51:39 +0300888 delete [] buf, buf = NULL, --retry) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800889 if (getPruneList) {
890 android_logger_get_prune_list(logger_list, buf, len);
891 } else {
892 android_logger_get_statistics(logger_list, buf, len);
893 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800894 buf[len-1] = '\0';
Traian Schiau59763032015-04-10 15:51:39 +0300895 if (atol(buf) < 3) {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800896 delete [] buf;
897 buf = NULL;
898 break;
899 }
Traian Schiau59763032015-04-10 15:51:39 +0300900 size_t ret = atol(buf) + 1;
901 if (ret <= len) {
902 len = ret;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800903 break;
904 }
Traian Schiau59763032015-04-10 15:51:39 +0300905 len = ret;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800906 }
907
908 if (!buf) {
Traian Schiau59763032015-04-10 15:51:39 +0300909 logcat_panic(false, "failed to read data");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800910 }
911
912 // remove trailing FF
913 char *cp = buf + len - 1;
914 *cp = '\0';
915 bool truncated = *--cp != '\f';
916 if (!truncated) {
917 *cp = '\0';
918 }
919
920 // squash out the byte count
921 cp = buf;
922 if (!truncated) {
Mark Salyzyn22e287d2014-03-21 13:12:16 -0700923 while (isdigit(*cp)) {
924 ++cp;
925 }
926 if (*cp == '\n') {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800927 ++cp;
928 }
929 }
930
931 printf("%s", cp);
932 delete [] buf;
Traian Schiau59763032015-04-10 15:51:39 +0300933 return EXIT_SUCCESS;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800934 }
935
936
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800937 if (getLogSize) {
Traian Schiau59763032015-04-10 15:51:39 +0300938 return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800939 }
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800940 if (setLogSize || setPruneList) {
Traian Schiau59763032015-04-10 15:51:39 +0300941 return EXIT_SUCCESS;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800942 }
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800943 if (clearLog) {
Traian Schiau59763032015-04-10 15:51:39 +0300944 return EXIT_SUCCESS;
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800945 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800946
947 //LOG_EVENT_INT(10, 12345);
948 //LOG_EVENT_LONG(11, 0x1122334455667788LL);
949 //LOG_EVENT_STRING(0, "whassup, doc?");
950
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800951 dev = NULL;
Mark Salyzyn5f6738a2015-02-27 13:41:34 -0800952 log_device_t unexpected("unexpected", false);
Mark Salyzyn95132e92013-11-22 10:55:48 -0800953 while (1) {
954 struct log_msg log_msg;
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800955 log_device_t* d;
Mark Salyzyn95132e92013-11-22 10:55:48 -0800956 int ret = android_logger_list_read(logger_list, &log_msg);
957
958 if (ret == 0) {
Traian Schiau59763032015-04-10 15:51:39 +0300959 logcat_panic(false, "read: unexpected EOF!\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -0800960 }
961
962 if (ret < 0) {
963 if (ret == -EAGAIN) {
964 break;
965 }
966
967 if (ret == -EIO) {
Traian Schiau59763032015-04-10 15:51:39 +0300968 logcat_panic(false, "read: unexpected EOF!\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -0800969 }
970 if (ret == -EINVAL) {
Traian Schiau59763032015-04-10 15:51:39 +0300971 logcat_panic(false, "read: unexpected length.\n");
Mark Salyzyn95132e92013-11-22 10:55:48 -0800972 }
Traian Schiau59763032015-04-10 15:51:39 +0300973 logcat_panic(false, "logcat read failure");
Mark Salyzyn95132e92013-11-22 10:55:48 -0800974 }
975
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800976 for(d = devices; d; d = d->next) {
977 if (android_name_to_log_id(d->device) == log_msg.id()) {
Mark Salyzyn95132e92013-11-22 10:55:48 -0800978 break;
979 }
980 }
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800981 if (!d) {
Traian Schiau59763032015-04-10 15:51:39 +0300982 g_devCount = 2; // set to Multiple
Mark Salyzyn9421b0c2015-02-26 14:33:35 -0800983 d = &unexpected;
984 d->binary = log_msg.id() == LOG_ID_EVENTS;
Mark Salyzyn95132e92013-11-22 10:55:48 -0800985 }
986
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800987 if (dev != d) {
988 dev = d;
Traian Schiau59763032015-04-10 15:51:39 +0300989 maybePrintStart(dev, printDividers);
Mark Salyzyn7b30ff82015-01-26 13:41:33 -0800990 }
Traian Schiau59763032015-04-10 15:51:39 +0300991 if (g_printBinary) {
992 printBinary(&log_msg);
Mark Salyzyn95132e92013-11-22 10:55:48 -0800993 } else {
Traian Schiau59763032015-04-10 15:51:39 +0300994 processBuffer(dev, &log_msg);
Mark Salyzyn95132e92013-11-22 10:55:48 -0800995 }
996 }
997
998 android_logger_list_free(logger_list);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800999
Traian Schiau59763032015-04-10 15:51:39 +03001000 return EXIT_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001001}