log_read.c revision 18a5432158ad43b8faefe4950b30e760200ce0b4
1/* 2** Copyright 2013-2014, The Android Open Source Project 3** 4** Licensed under the Apache License, Version 2.0 (the "License"); 5** you may not use this file except in compliance with the License. 6** You may obtain a copy of the License at 7** 8** http://www.apache.org/licenses/LICENSE-2.0 9** 10** Unless required by applicable law or agreed to in writing, software 11** distributed under the License is distributed on an "AS IS" BASIS, 12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13** See the License for the specific language governing permissions and 14** limitations under the License. 15*/ 16 17#include <errno.h> 18#include <fcntl.h> 19#include <signal.h> 20#include <stddef.h> 21#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */ 22#include <stdlib.h> 23#include <string.h> 24#include <unistd.h> 25 26#include <cutils/list.h> 27#include <cutils/sockets.h> 28#include <log/log.h> 29#include <log/logger.h> 30 31/* branchless on many architectures. */ 32#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y)))) 33 34#define WEAK __attribute__((weak)) 35#define UNUSED __attribute__((unused)) 36 37/* Private copy of ../libcutils/socket_local_client.c prevent library loops */ 38 39#ifdef HAVE_WINSOCK 40 41int WEAK socket_local_client(const char *name, int namespaceId, int type) 42{ 43 errno = ENOSYS; 44 return -ENOSYS; 45} 46 47#else /* !HAVE_WINSOCK */ 48 49#include <sys/socket.h> 50#include <sys/un.h> 51#include <sys/select.h> 52#include <sys/types.h> 53 54/* Private copy of ../libcutils/socket_local.h prevent library loops */ 55#define FILESYSTEM_SOCKET_PREFIX "/tmp/" 56#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/" 57/* End of ../libcutils/socket_local.h */ 58 59#define LISTEN_BACKLOG 4 60 61/* Documented in header file. */ 62int WEAK socket_make_sockaddr_un(const char *name, int namespaceId, 63 struct sockaddr_un *p_addr, socklen_t *alen) 64{ 65 memset (p_addr, 0, sizeof (*p_addr)); 66 size_t namelen; 67 68 switch (namespaceId) { 69 case ANDROID_SOCKET_NAMESPACE_ABSTRACT: 70#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE 71 namelen = strlen(name); 72 73 /* Test with length +1 for the *initial* '\0'. */ 74 if ((namelen + 1) > sizeof(p_addr->sun_path)) { 75 goto error; 76 } 77 78 /* 79 * Note: The path in this case is *not* supposed to be 80 * '\0'-terminated. ("man 7 unix" for the gory details.) 81 */ 82 83 p_addr->sun_path[0] = 0; 84 memcpy(p_addr->sun_path + 1, name, namelen); 85#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/ 86 /* this OS doesn't have the Linux abstract namespace */ 87 88 namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX); 89 /* unix_path_max appears to be missing on linux */ 90 if (namelen > sizeof(*p_addr) 91 - offsetof(struct sockaddr_un, sun_path) - 1) { 92 goto error; 93 } 94 95 strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX); 96 strcat(p_addr->sun_path, name); 97#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/ 98 break; 99 100 case ANDROID_SOCKET_NAMESPACE_RESERVED: 101 namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX); 102 /* unix_path_max appears to be missing on linux */ 103 if (namelen > sizeof(*p_addr) 104 - offsetof(struct sockaddr_un, sun_path) - 1) { 105 goto error; 106 } 107 108 strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX); 109 strcat(p_addr->sun_path, name); 110 break; 111 112 case ANDROID_SOCKET_NAMESPACE_FILESYSTEM: 113 namelen = strlen(name); 114 /* unix_path_max appears to be missing on linux */ 115 if (namelen > sizeof(*p_addr) 116 - offsetof(struct sockaddr_un, sun_path) - 1) { 117 goto error; 118 } 119 120 strcpy(p_addr->sun_path, name); 121 break; 122 123 default: 124 /* invalid namespace id */ 125 return -1; 126 } 127 128 p_addr->sun_family = AF_LOCAL; 129 *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; 130 return 0; 131error: 132 return -1; 133} 134 135/** 136 * connect to peer named "name" on fd 137 * returns same fd or -1 on error. 138 * fd is not closed on error. that's your job. 139 * 140 * Used by AndroidSocketImpl 141 */ 142int WEAK socket_local_client_connect(int fd, const char *name, int namespaceId, 143 int type UNUSED) 144{ 145 struct sockaddr_un addr; 146 socklen_t alen; 147 size_t namelen; 148 int err; 149 150 err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen); 151 152 if (err < 0) { 153 goto error; 154 } 155 156 if(connect(fd, (struct sockaddr *) &addr, alen) < 0) { 157 goto error; 158 } 159 160 return fd; 161 162error: 163 return -1; 164} 165 166/** 167 * connect to peer named "name" 168 * returns fd or -1 on error 169 */ 170int WEAK socket_local_client(const char *name, int namespaceId, int type) 171{ 172 int s; 173 174 s = socket(AF_LOCAL, type, 0); 175 if(s < 0) return -1; 176 177 if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) { 178 close(s); 179 return -1; 180 } 181 182 return s; 183} 184 185#endif /* !HAVE_WINSOCK */ 186/* End of ../libcutils/socket_local_client.c */ 187 188#define logger_for_each(logger, logger_list) \ 189 for (logger = node_to_item((logger_list)->node.next, struct logger, node); \ 190 logger != node_to_item(&(logger_list)->node, struct logger, node); \ 191 logger = node_to_item((logger)->node.next, struct logger, node)) 192 193/* In the future, we would like to make this list extensible */ 194static const char *LOG_NAME[LOG_ID_MAX] = { 195 [LOG_ID_MAIN] = "main", 196 [LOG_ID_RADIO] = "radio", 197 [LOG_ID_EVENTS] = "events", 198 [LOG_ID_SYSTEM] = "system" 199}; 200 201const char *android_log_id_to_name(log_id_t log_id) 202{ 203 if (log_id >= LOG_ID_MAX) { 204 log_id = LOG_ID_MAIN; 205 } 206 return LOG_NAME[log_id]; 207} 208 209log_id_t android_name_to_log_id(const char *logName) 210{ 211 const char *b; 212 int ret; 213 214 if (!logName) { 215 return -1; /* NB: log_id_t is unsigned */ 216 } 217 b = strrchr(logName, '/'); 218 if (!b) { 219 b = logName; 220 } else { 221 ++b; 222 } 223 224 for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) { 225 const char *l = LOG_NAME[ret]; 226 if (l && !strcmp(b, l)) { 227 return ret; 228 } 229 } 230 return -1; /* should never happen */ 231} 232 233struct logger_list { 234 struct listnode node; 235 int mode; 236 unsigned int tail; 237 pid_t pid; 238 int sock; 239}; 240 241struct logger { 242 struct listnode node; 243 struct logger_list *top; 244 log_id_t id; 245}; 246 247/* android_logger_alloc unimplemented, no use case */ 248/* android_logger_free not exported */ 249static void android_logger_free(struct logger *logger) 250{ 251 if (!logger) { 252 return; 253 } 254 255 list_remove(&logger->node); 256 257 free(logger); 258} 259 260/* android_logger_alloc unimplemented, no use case */ 261 262/* method for getting the associated sublog id */ 263log_id_t android_logger_get_id(struct logger *logger) 264{ 265 return logger->id; 266} 267 268/* worker for sending the command to the logger */ 269static ssize_t send_log_msg(struct logger *logger, 270 const char *msg, char *buf, size_t buf_size) 271{ 272 ssize_t ret; 273 int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, 274 SOCK_STREAM); 275 if (sock < 0) { 276 ret = sock; 277 goto done; 278 } 279 280 if (msg) { 281 snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1); 282 } 283 284 ret = write(sock, buf, strlen(buf) + 1); 285 if (ret <= 0) { 286 goto done; 287 } 288 289 ret = read(sock, buf, buf_size); 290 291done: 292 if ((ret == -1) && errno) { 293 ret = -errno; 294 } 295 close(sock); 296 return ret; 297} 298 299static int check_log_success(char *buf, ssize_t ret) 300{ 301 if (ret < 0) { 302 return ret; 303 } 304 305 if (strncmp(buf, "success", 7)) { 306 return -1; 307 } 308 309 return 0; 310} 311 312int android_logger_clear(struct logger *logger) 313{ 314 char buf[512]; 315 316 return check_log_success(buf, 317 send_log_msg(logger, "clear %d", buf, sizeof(buf))); 318} 319 320/* returns the total size of the log's ring buffer */ 321long android_logger_get_log_size(struct logger *logger) 322{ 323 char buf[512]; 324 325 ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf)); 326 if (ret < 0) { 327 return ret; 328 } 329 330 if ((buf[0] < '0') || ('9' < buf[0])) { 331 return -1; 332 } 333 334 return atol(buf); 335} 336 337#ifdef USERDEBUG_BUILD 338 339int android_logger_set_log_size(struct logger *logger, unsigned long size) 340{ 341 char buf[512]; 342 343 snprintf(buf, sizeof(buf), "setLogSize %d %lu", 344 logger ? logger->id : (unsigned) -1, size); 345 346 return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf))); 347} 348 349#endif /* USERDEBUG_BUILD */ 350 351/* 352 * returns the readable size of the log's ring buffer (that is, amount of the 353 * log consumed) 354 */ 355long android_logger_get_log_readable_size(struct logger *logger) 356{ 357 char buf[512]; 358 359 ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf)); 360 if (ret < 0) { 361 return ret; 362 } 363 364 if ((buf[0] < '0') || ('9' < buf[0])) { 365 return -1; 366 } 367 368 return atol(buf); 369} 370 371/* 372 * returns the logger version 373 */ 374int android_logger_get_log_version(struct logger *logger UNUSED) 375{ 376 return 3; 377} 378 379/* 380 * returns statistics 381 */ 382ssize_t android_logger_get_statistics(struct logger_list *logger_list, 383 char *buf, size_t len) 384{ 385 struct listnode *node; 386 struct logger *logger; 387 char *cp = buf; 388 size_t remaining = len; 389 size_t n; 390 391 n = snprintf(cp, remaining, "getStatistics"); 392 n = min(n, remaining); 393 remaining -= n; 394 cp += n; 395 396 logger_for_each(logger, logger_list) { 397 n = snprintf(cp, remaining, " %d", logger->id); 398 n = min(n, remaining); 399 remaining -= n; 400 cp += n; 401 } 402 return send_log_msg(NULL, NULL, buf, len); 403} 404 405#ifdef USERDEBUG_BUILD 406 407ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED, 408 char *buf, size_t len) 409{ 410 return send_log_msg(NULL, "getPruneList", buf, len); 411} 412 413int android_logger_set_prune_list(struct logger_list *logger_list UNUSED, 414 char *buf, size_t len) 415{ 416 const char cmd[] = "setPruneList "; 417 const size_t cmdlen = sizeof(cmd) - 1; 418 419 if (strlen(buf) > (len - cmdlen)) { 420 return -ENOMEM; /* KISS */ 421 } 422 memmove(buf + cmdlen, buf, len - cmdlen); 423 buf[len - 1] = '\0'; 424 memcpy(buf, cmd, cmdlen); 425 426 return check_log_success(buf, send_log_msg(NULL, NULL, buf, len)); 427} 428 429#endif /* USERDEBUG_BUILD */ 430 431struct logger_list *android_logger_list_alloc(int mode, 432 unsigned int tail, 433 pid_t pid) 434{ 435 struct logger_list *logger_list; 436 437 logger_list = calloc(1, sizeof(*logger_list)); 438 if (!logger_list) { 439 return NULL; 440 } 441 442 list_init(&logger_list->node); 443 logger_list->mode = mode; 444 logger_list->tail = tail; 445 logger_list->pid = pid; 446 logger_list->sock = -1; 447 448 return logger_list; 449} 450 451/* android_logger_list_register unimplemented, no use case */ 452/* android_logger_list_unregister unimplemented, no use case */ 453 454/* Open the named log and add it to the logger list */ 455struct logger *android_logger_open(struct logger_list *logger_list, 456 log_id_t id) 457{ 458 struct listnode *node; 459 struct logger *logger; 460 char *n; 461 462 if (!logger_list || (id >= LOG_ID_MAX)) { 463 goto err; 464 } 465 466 logger_for_each(logger, logger_list) { 467 if (logger->id == id) { 468 goto ok; 469 } 470 } 471 472 logger = calloc(1, sizeof(*logger)); 473 if (!logger) { 474 goto err; 475 } 476 477 logger->id = id; 478 list_add_tail(&logger_list->node, &logger->node); 479 logger->top = logger_list; 480 goto ok; 481 482err: 483 logger = NULL; 484ok: 485 return logger; 486} 487 488/* Open the single named log and make it part of a new logger list */ 489struct logger_list *android_logger_list_open(log_id_t id, 490 int mode, 491 unsigned int tail, 492 pid_t pid) 493{ 494 struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid); 495 if (!logger_list) { 496 return NULL; 497 } 498 499 if (!android_logger_open(logger_list, id)) { 500 android_logger_list_free(logger_list); 501 return NULL; 502 } 503 504 return logger_list; 505} 506 507static void caught_signal(int signum UNUSED) 508{ 509} 510 511/* Read from the selected logs */ 512int android_logger_list_read(struct logger_list *logger_list, 513 struct log_msg *log_msg) 514{ 515 int ret, e; 516 struct logger *logger; 517 struct sigaction ignore; 518 struct sigaction old_sigaction; 519 unsigned int old_alarm = 0; 520 521 if (!logger_list) { 522 return -EINVAL; 523 } 524 525 if (logger_list->mode & O_NONBLOCK) { 526 memset(&ignore, 0, sizeof(ignore)); 527 ignore.sa_handler = caught_signal; 528 sigemptyset(&ignore.sa_mask); 529 } 530 531 if (logger_list->sock < 0) { 532 char buffer[256], *cp, c; 533 534 int sock = socket_local_client("logdr", 535 ANDROID_SOCKET_NAMESPACE_RESERVED, 536 SOCK_SEQPACKET); 537 if (sock < 0) { 538 if ((sock == -1) && errno) { 539 return -errno; 540 } 541 return sock; 542 } 543 544 strcpy(buffer, 545 (logger_list->mode & O_NONBLOCK) ? "dumpAndClose" : "stream"); 546 cp = buffer + strlen(buffer); 547 548 strcpy(cp, " lids"); 549 cp += 5; 550 c = '='; 551 int remaining = sizeof(buffer) - (cp - buffer); 552 logger_for_each(logger, logger_list) { 553 ret = snprintf(cp, remaining, "%c%u", c, logger->id); 554 ret = min(ret, remaining); 555 remaining -= ret; 556 cp += ret; 557 c = ','; 558 } 559 560 if (logger_list->tail) { 561 ret = snprintf(cp, remaining, " tail=%u", logger_list->tail); 562 ret = min(ret, remaining); 563 remaining -= ret; 564 cp += ret; 565 } 566 567 if (logger_list->pid) { 568 ret = snprintf(cp, remaining, " pid=%u", logger_list->pid); 569 ret = min(ret, remaining); 570 remaining -= ret; 571 cp += ret; 572 } 573 574 if (logger_list->mode & O_NONBLOCK) { 575 /* Deal with an unresponsive logd */ 576 sigaction(SIGALRM, &ignore, &old_sigaction); 577 old_alarm = alarm(30); 578 } 579 ret = write(sock, buffer, cp - buffer); 580 e = errno; 581 if (logger_list->mode & O_NONBLOCK) { 582 if (e == EINTR) { 583 e = ETIMEDOUT; 584 } 585 alarm(old_alarm); 586 sigaction(SIGALRM, &old_sigaction, NULL); 587 } 588 589 if (ret <= 0) { 590 close(sock); 591 if ((ret == -1) && e) { 592 return -e; 593 } 594 if (ret == 0) { 595 return -EIO; 596 } 597 return ret; 598 } 599 600 logger_list->sock = sock; 601 } 602 603 ret = 0; 604 while(1) { 605 memset(log_msg, 0, sizeof(*log_msg)); 606 607 if (logger_list->mode & O_NONBLOCK) { 608 /* particularily useful if tombstone is reporting for logd */ 609 sigaction(SIGALRM, &ignore, &old_sigaction); 610 old_alarm = alarm(30); 611 } 612 /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */ 613 ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0); 614 e = errno; 615 if (logger_list->mode & O_NONBLOCK) { 616 if ((ret == 0) || (e == EINTR)) { 617 e = EAGAIN; 618 ret = -1; 619 } 620 alarm(old_alarm); 621 sigaction(SIGALRM, &old_sigaction, NULL); 622 } 623 624 if (ret <= 0) { 625 if ((ret == -1) && e) { 626 return -e; 627 } 628 return ret; 629 } 630 631 logger_for_each(logger, logger_list) { 632 if (log_msg->entry.lid == logger->id) { 633 return ret; 634 } 635 } 636 } 637 /* NOTREACH */ 638 return ret; 639} 640 641/* Close all the logs */ 642void android_logger_list_free(struct logger_list *logger_list) 643{ 644 if (logger_list == NULL) { 645 return; 646 } 647 648 while (!list_empty(&logger_list->node)) { 649 struct listnode *node = list_head(&logger_list->node); 650 struct logger *logger = node_to_item(node, struct logger, node); 651 android_logger_free(logger); 652 } 653 654 if (logger_list->sock >= 0) { 655 close (logger_list->sock); 656 } 657 658 free(logger_list); 659} 660