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 <inttypes.h> 20#include <poll.h> 21#include <signal.h> 22#include <stdbool.h> 23#include <stddef.h> 24#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */ 25#include <stdlib.h> 26#include <string.h> 27#include <sys/cdefs.h> 28#include <unistd.h> 29 30#include <cutils/list.h> 31#include <cutils/sockets.h> 32#include <log/log.h> 33#include <log/logger.h> 34#include <private/android_filesystem_config.h> 35#include <private/android_logger.h> 36 37/* branchless on many architectures. */ 38#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y)))) 39 40#if (defined(USE_MINGW) || defined(HAVE_WINSOCK)) 41#define WEAK static 42#else 43#define WEAK __attribute__((weak)) 44#endif 45#ifndef __unused 46#define __unused __attribute__((unused)) 47#endif 48 49/* Private copy of ../libcutils/socket_local_client.c prevent library loops */ 50 51#ifdef HAVE_WINSOCK 52 53int WEAK socket_local_client(const char *name, int namespaceId, int type) 54{ 55 errno = ENOSYS; 56 return -ENOSYS; 57} 58 59#else /* !HAVE_WINSOCK */ 60 61#include <sys/socket.h> 62#include <sys/un.h> 63#include <sys/select.h> 64#include <sys/types.h> 65 66/* Private copy of ../libcutils/socket_local.h prevent library loops */ 67#define FILESYSTEM_SOCKET_PREFIX "/tmp/" 68#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/" 69/* End of ../libcutils/socket_local.h */ 70 71#define LISTEN_BACKLOG 4 72 73/* Documented in header file. */ 74int WEAK socket_make_sockaddr_un(const char *name, int namespaceId, 75 struct sockaddr_un *p_addr, socklen_t *alen) 76{ 77 memset (p_addr, 0, sizeof (*p_addr)); 78 size_t namelen; 79 80 switch (namespaceId) { 81 case ANDROID_SOCKET_NAMESPACE_ABSTRACT: 82#if defined(__linux__) 83 namelen = strlen(name); 84 85 /* Test with length +1 for the *initial* '\0'. */ 86 if ((namelen + 1) > sizeof(p_addr->sun_path)) { 87 goto error; 88 } 89 90 /* 91 * Note: The path in this case is *not* supposed to be 92 * '\0'-terminated. ("man 7 unix" for the gory details.) 93 */ 94 95 p_addr->sun_path[0] = 0; 96 memcpy(p_addr->sun_path + 1, name, namelen); 97#else 98 /* this OS doesn't have the Linux abstract namespace */ 99 100 namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX); 101 /* unix_path_max appears to be missing on linux */ 102 if (namelen > sizeof(*p_addr) 103 - offsetof(struct sockaddr_un, sun_path) - 1) { 104 goto error; 105 } 106 107 strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX); 108 strcat(p_addr->sun_path, name); 109#endif 110 break; 111 112 case ANDROID_SOCKET_NAMESPACE_RESERVED: 113 namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX); 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, ANDROID_RESERVED_SOCKET_PREFIX); 121 strcat(p_addr->sun_path, name); 122 break; 123 124 case ANDROID_SOCKET_NAMESPACE_FILESYSTEM: 125 namelen = strlen(name); 126 /* unix_path_max appears to be missing on linux */ 127 if (namelen > sizeof(*p_addr) 128 - offsetof(struct sockaddr_un, sun_path) - 1) { 129 goto error; 130 } 131 132 strcpy(p_addr->sun_path, name); 133 break; 134 135 default: 136 /* invalid namespace id */ 137 return -1; 138 } 139 140 p_addr->sun_family = AF_LOCAL; 141 *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; 142 return 0; 143error: 144 return -1; 145} 146 147/** 148 * connect to peer named "name" on fd 149 * returns same fd or -1 on error. 150 * fd is not closed on error. that's your job. 151 * 152 * Used by AndroidSocketImpl 153 */ 154int WEAK socket_local_client_connect(int fd, const char *name, int namespaceId, 155 int type __unused) 156{ 157 struct sockaddr_un addr; 158 socklen_t alen; 159 int err; 160 161 err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen); 162 163 if (err < 0) { 164 goto error; 165 } 166 167 if(connect(fd, (struct sockaddr *) &addr, alen) < 0) { 168 goto error; 169 } 170 171 return fd; 172 173error: 174 return -1; 175} 176 177/** 178 * connect to peer named "name" 179 * returns fd or -1 on error 180 */ 181int WEAK socket_local_client(const char *name, int namespaceId, int type) 182{ 183 int s; 184 185 s = socket(AF_LOCAL, type, 0); 186 if(s < 0) return -1; 187 188 if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) { 189 close(s); 190 return -1; 191 } 192 193 return s; 194} 195 196#endif /* !HAVE_WINSOCK */ 197/* End of ../libcutils/socket_local_client.c */ 198 199#define logger_for_each(logger, logger_list) \ 200 for (logger = node_to_item((logger_list)->node.next, struct logger, node); \ 201 logger != node_to_item(&(logger_list)->node, struct logger, node); \ 202 logger = node_to_item((logger)->node.next, struct logger, node)) 203 204/* In the future, we would like to make this list extensible */ 205static const char *LOG_NAME[LOG_ID_MAX] = { 206 [LOG_ID_MAIN] = "main", 207 [LOG_ID_RADIO] = "radio", 208 [LOG_ID_EVENTS] = "events", 209 [LOG_ID_SYSTEM] = "system", 210 [LOG_ID_CRASH] = "crash", 211 [LOG_ID_KERNEL] = "kernel", 212}; 213 214const char *android_log_id_to_name(log_id_t log_id) 215{ 216 if (log_id >= LOG_ID_MAX) { 217 log_id = LOG_ID_MAIN; 218 } 219 return LOG_NAME[log_id]; 220} 221 222log_id_t android_name_to_log_id(const char *logName) 223{ 224 const char *b; 225 int ret; 226 227 if (!logName) { 228 return -1; /* NB: log_id_t is unsigned */ 229 } 230 b = strrchr(logName, '/'); 231 if (!b) { 232 b = logName; 233 } else { 234 ++b; 235 } 236 237 for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) { 238 const char *l = LOG_NAME[ret]; 239 if (l && !strcmp(b, l)) { 240 return ret; 241 } 242 } 243 return -1; /* should never happen */ 244} 245 246struct logger_list { 247 struct listnode node; 248 int mode; 249 unsigned int tail; 250 log_time start; 251 pid_t pid; 252 int sock; 253}; 254 255struct logger { 256 struct listnode node; 257 struct logger_list *top; 258 log_id_t id; 259}; 260 261/* android_logger_alloc unimplemented, no use case */ 262/* android_logger_free not exported */ 263static void android_logger_free(struct logger *logger) 264{ 265 if (!logger) { 266 return; 267 } 268 269 list_remove(&logger->node); 270 271 free(logger); 272} 273 274/* android_logger_alloc unimplemented, no use case */ 275 276/* method for getting the associated sublog id */ 277log_id_t android_logger_get_id(struct logger *logger) 278{ 279 return logger->id; 280} 281 282/* worker for sending the command to the logger */ 283static ssize_t send_log_msg(struct logger *logger, 284 const char *msg, char *buf, size_t buf_size) 285{ 286 ssize_t ret; 287 size_t len; 288 char *cp; 289 int errno_save = 0; 290 int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, 291 SOCK_STREAM); 292 if (sock < 0) { 293 return sock; 294 } 295 296 if (msg) { 297 snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1); 298 } 299 300 len = strlen(buf) + 1; 301 ret = TEMP_FAILURE_RETRY(write(sock, buf, len)); 302 if (ret <= 0) { 303 goto done; 304 } 305 306 len = buf_size; 307 cp = buf; 308 while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) { 309 struct pollfd p; 310 311 if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) { 312 break; 313 } 314 315 len -= ret; 316 cp += ret; 317 318 memset(&p, 0, sizeof(p)); 319 p.fd = sock; 320 p.events = POLLIN; 321 322 /* Give other side 20ms to refill pipe */ 323 ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20)); 324 325 if (ret <= 0) { 326 break; 327 } 328 329 if (!(p.revents & POLLIN)) { 330 ret = 0; 331 break; 332 } 333 } 334 335 if (ret >= 0) { 336 ret += buf_size - len; 337 } 338 339done: 340 if ((ret == -1) && errno) { 341 errno_save = errno; 342 } 343 close(sock); 344 if (errno_save) { 345 errno = errno_save; 346 } 347 return ret; 348} 349 350static int check_log_success(char *buf, ssize_t ret) 351{ 352 if (ret < 0) { 353 return ret; 354 } 355 356 if (strncmp(buf, "success", 7)) { 357 errno = EINVAL; 358 return -1; 359 } 360 361 return 0; 362} 363 364/* Determine the credentials of the caller */ 365static bool uid_has_log_permission(uid_t uid) 366{ 367 return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT); 368} 369 370static uid_t get_best_effective_uid() 371{ 372 uid_t euid; 373 uid_t uid; 374 gid_t gid; 375 ssize_t i; 376 static uid_t last_uid = (uid_t) -1; 377 378 if (last_uid != (uid_t) -1) { 379 return last_uid; 380 } 381 uid = getuid(); 382 if (uid_has_log_permission(uid)) { 383 return last_uid = uid; 384 } 385 euid = geteuid(); 386 if (uid_has_log_permission(euid)) { 387 return last_uid = euid; 388 } 389 gid = getgid(); 390 if (uid_has_log_permission(gid)) { 391 return last_uid = gid; 392 } 393 gid = getegid(); 394 if (uid_has_log_permission(gid)) { 395 return last_uid = gid; 396 } 397 i = getgroups((size_t) 0, NULL); 398 if (i > 0) { 399 gid_t list[i]; 400 401 getgroups(i, list); 402 while (--i >= 0) { 403 if (uid_has_log_permission(list[i])) { 404 return last_uid = list[i]; 405 } 406 } 407 } 408 return last_uid = uid; 409} 410 411int android_logger_clear(struct logger *logger) 412{ 413 char buf[512]; 414 415 if (logger->top->mode & ANDROID_LOG_PSTORE) { 416 if (uid_has_log_permission(get_best_effective_uid())) { 417 return unlink("/sys/fs/pstore/pmsg-ramoops-0"); 418 } 419 errno = EPERM; 420 return -1; 421 } 422 return check_log_success(buf, 423 send_log_msg(logger, "clear %d", buf, sizeof(buf))); 424} 425 426/* returns the total size of the log's ring buffer */ 427long android_logger_get_log_size(struct logger *logger) 428{ 429 char buf[512]; 430 431 ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf)); 432 if (ret < 0) { 433 return ret; 434 } 435 436 if ((buf[0] < '0') || ('9' < buf[0])) { 437 return -1; 438 } 439 440 return atol(buf); 441} 442 443int android_logger_set_log_size(struct logger *logger, unsigned long size) 444{ 445 char buf[512]; 446 447 snprintf(buf, sizeof(buf), "setLogSize %d %lu", 448 logger ? logger->id : (unsigned) -1, size); 449 450 return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf))); 451} 452 453/* 454 * returns the readable size of the log's ring buffer (that is, amount of the 455 * log consumed) 456 */ 457long android_logger_get_log_readable_size(struct logger *logger) 458{ 459 char buf[512]; 460 461 ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf)); 462 if (ret < 0) { 463 return ret; 464 } 465 466 if ((buf[0] < '0') || ('9' < buf[0])) { 467 return -1; 468 } 469 470 return atol(buf); 471} 472 473/* 474 * returns the logger version 475 */ 476int android_logger_get_log_version(struct logger *logger __unused) 477{ 478 return 3; 479} 480 481/* 482 * returns statistics 483 */ 484ssize_t android_logger_get_statistics(struct logger_list *logger_list, 485 char *buf, size_t len) 486{ 487 struct logger *logger; 488 char *cp = buf; 489 size_t remaining = len; 490 size_t n; 491 492 n = snprintf(cp, remaining, "getStatistics"); 493 n = min(n, remaining); 494 remaining -= n; 495 cp += n; 496 497 logger_for_each(logger, logger_list) { 498 n = snprintf(cp, remaining, " %d", logger->id); 499 n = min(n, remaining); 500 remaining -= n; 501 cp += n; 502 } 503 return send_log_msg(NULL, NULL, buf, len); 504} 505 506ssize_t android_logger_get_prune_list(struct logger_list *logger_list __unused, 507 char *buf, size_t len) 508{ 509 return send_log_msg(NULL, "getPruneList", buf, len); 510} 511 512int android_logger_set_prune_list(struct logger_list *logger_list __unused, 513 char *buf, size_t len) 514{ 515 const char cmd[] = "setPruneList "; 516 const size_t cmdlen = sizeof(cmd) - 1; 517 518 if (strlen(buf) > (len - cmdlen)) { 519 return -ENOMEM; /* KISS */ 520 } 521 memmove(buf + cmdlen, buf, len - cmdlen); 522 buf[len - 1] = '\0'; 523 memcpy(buf, cmd, cmdlen); 524 525 return check_log_success(buf, send_log_msg(NULL, NULL, buf, len)); 526} 527 528struct logger_list *android_logger_list_alloc(int mode, 529 unsigned int tail, 530 pid_t pid) 531{ 532 struct logger_list *logger_list; 533 534 logger_list = calloc(1, sizeof(*logger_list)); 535 if (!logger_list) { 536 return NULL; 537 } 538 539 list_init(&logger_list->node); 540 logger_list->mode = mode; 541 logger_list->start.tv_sec = 0; 542 logger_list->start.tv_nsec = 0; 543 logger_list->tail = tail; 544 logger_list->pid = pid; 545 logger_list->sock = -1; 546 547 return logger_list; 548} 549 550struct logger_list *android_logger_list_alloc_time(int mode, 551 log_time start, 552 pid_t pid) 553{ 554 struct logger_list *logger_list; 555 556 logger_list = calloc(1, sizeof(*logger_list)); 557 if (!logger_list) { 558 return NULL; 559 } 560 561 list_init(&logger_list->node); 562 logger_list->mode = mode; 563 logger_list->start = start; 564 logger_list->tail = 0; 565 logger_list->pid = pid; 566 logger_list->sock = -1; 567 568 return logger_list; 569} 570 571/* android_logger_list_register unimplemented, no use case */ 572/* android_logger_list_unregister unimplemented, no use case */ 573 574/* Open the named log and add it to the logger list */ 575struct logger *android_logger_open(struct logger_list *logger_list, 576 log_id_t id) 577{ 578 struct logger *logger; 579 580 if (!logger_list || (id >= LOG_ID_MAX)) { 581 goto err; 582 } 583 584 logger_for_each(logger, logger_list) { 585 if (logger->id == id) { 586 goto ok; 587 } 588 } 589 590 logger = calloc(1, sizeof(*logger)); 591 if (!logger) { 592 goto err; 593 } 594 595 logger->id = id; 596 list_add_tail(&logger_list->node, &logger->node); 597 logger->top = logger_list; 598 goto ok; 599 600err: 601 logger = NULL; 602ok: 603 return logger; 604} 605 606/* Open the single named log and make it part of a new logger list */ 607struct logger_list *android_logger_list_open(log_id_t id, 608 int mode, 609 unsigned int tail, 610 pid_t pid) 611{ 612 struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid); 613 if (!logger_list) { 614 return NULL; 615 } 616 617 if (!android_logger_open(logger_list, id)) { 618 android_logger_list_free(logger_list); 619 return NULL; 620 } 621 622 return logger_list; 623} 624 625static int android_logger_list_read_pstore(struct logger_list *logger_list, 626 struct log_msg *log_msg) 627{ 628 ssize_t ret; 629 off_t current, next; 630 uid_t uid; 631 struct logger *logger; 632 struct __attribute__((__packed__)) { 633 android_pmsg_log_header_t p; 634 android_log_header_t l; 635 } buf; 636 static uint8_t preread_count; 637 638 memset(log_msg, 0, sizeof(*log_msg)); 639 640 if (logger_list->sock < 0) { 641 int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY); 642 643 if (fd < 0) { 644 return -errno; 645 } 646 logger_list->sock = fd; 647 preread_count = 0; 648 } 649 650 ret = 0; 651 while(1) { 652 if (preread_count < sizeof(buf)) { 653 ret = TEMP_FAILURE_RETRY(read(logger_list->sock, 654 &buf.p.magic + preread_count, 655 sizeof(buf) - preread_count)); 656 if (ret < 0) { 657 return -errno; 658 } 659 preread_count += ret; 660 } 661 if (preread_count != sizeof(buf)) { 662 return preread_count ? -EIO : -EAGAIN; 663 } 664 if ((buf.p.magic != LOGGER_MAGIC) 665 || (buf.p.len <= sizeof(buf)) 666 || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) 667 || (buf.l.id >= LOG_ID_MAX) 668 || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) { 669 do { 670 memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count); 671 } while (preread_count && (buf.p.magic != LOGGER_MAGIC)); 672 continue; 673 } 674 preread_count = 0; 675 676 logger_for_each(logger, logger_list) { 677 if (buf.l.id != logger->id) { 678 continue; 679 } 680 681 if ((logger_list->start.tv_sec || logger_list->start.tv_nsec) 682 && ((logger_list->start.tv_sec > buf.l.realtime.tv_sec) 683 || ((logger_list->start.tv_sec == buf.l.realtime.tv_sec) 684 && (logger_list->start.tv_nsec > buf.l.realtime.tv_nsec)))) { 685 break; 686 } 687 688 if (logger_list->pid && (logger_list->pid != buf.p.pid)) { 689 break; 690 } 691 692 uid = get_best_effective_uid(); 693 if (!uid_has_log_permission(uid) && (uid != buf.p.uid)) { 694 break; 695 } 696 697 ret = TEMP_FAILURE_RETRY(read(logger_list->sock, 698 log_msg->entry_v3.msg, 699 buf.p.len - sizeof(buf))); 700 if (ret < 0) { 701 return -errno; 702 } 703 if (ret != (ssize_t)(buf.p.len - sizeof(buf))) { 704 return -EIO; 705 } 706 707 log_msg->entry_v3.len = buf.p.len - sizeof(buf); 708 log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3); 709 log_msg->entry_v3.pid = buf.p.pid; 710 log_msg->entry_v3.tid = buf.l.tid; 711 log_msg->entry_v3.sec = buf.l.realtime.tv_sec; 712 log_msg->entry_v3.nsec = buf.l.realtime.tv_nsec; 713 log_msg->entry_v3.lid = buf.l.id; 714 715 return ret; 716 } 717 718 current = TEMP_FAILURE_RETRY(lseek(logger_list->sock, 719 (off_t)0, SEEK_CUR)); 720 if (current < 0) { 721 return -errno; 722 } 723 next = TEMP_FAILURE_RETRY(lseek(logger_list->sock, 724 (off_t)(buf.p.len - sizeof(buf)), 725 SEEK_CUR)); 726 if (next < 0) { 727 return -errno; 728 } 729 if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) { 730 return -EIO; 731 } 732 } 733} 734 735static void caught_signal(int signum __unused) 736{ 737} 738 739/* Read from the selected logs */ 740int android_logger_list_read(struct logger_list *logger_list, 741 struct log_msg *log_msg) 742{ 743 int ret, e; 744 struct logger *logger; 745 struct sigaction ignore; 746 struct sigaction old_sigaction; 747 unsigned int old_alarm = 0; 748 749 if (!logger_list) { 750 return -EINVAL; 751 } 752 753 if (logger_list->mode & ANDROID_LOG_PSTORE) { 754 return android_logger_list_read_pstore(logger_list, log_msg); 755 } 756 757 if (logger_list->mode & ANDROID_LOG_NONBLOCK) { 758 memset(&ignore, 0, sizeof(ignore)); 759 ignore.sa_handler = caught_signal; 760 sigemptyset(&ignore.sa_mask); 761 } 762 763 if (logger_list->sock < 0) { 764 char buffer[256], *cp, c; 765 766 int sock = socket_local_client("logdr", 767 ANDROID_SOCKET_NAMESPACE_RESERVED, 768 SOCK_SEQPACKET); 769 if (sock < 0) { 770 if ((sock == -1) && errno) { 771 return -errno; 772 } 773 return sock; 774 } 775 776 strcpy(buffer, 777 (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream"); 778 cp = buffer + strlen(buffer); 779 780 strcpy(cp, " lids"); 781 cp += 5; 782 c = '='; 783 int remaining = sizeof(buffer) - (cp - buffer); 784 logger_for_each(logger, logger_list) { 785 ret = snprintf(cp, remaining, "%c%u", c, logger->id); 786 ret = min(ret, remaining); 787 remaining -= ret; 788 cp += ret; 789 c = ','; 790 } 791 792 if (logger_list->tail) { 793 ret = snprintf(cp, remaining, " tail=%u", logger_list->tail); 794 ret = min(ret, remaining); 795 remaining -= ret; 796 cp += ret; 797 } 798 799 if (logger_list->start.tv_sec || logger_list->start.tv_nsec) { 800 ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32, 801 logger_list->start.tv_sec, 802 logger_list->start.tv_nsec); 803 ret = min(ret, remaining); 804 remaining -= ret; 805 cp += ret; 806 } 807 808 if (logger_list->pid) { 809 ret = snprintf(cp, remaining, " pid=%u", logger_list->pid); 810 ret = min(ret, remaining); 811 remaining -= ret; 812 cp += ret; 813 } 814 815 if (logger_list->mode & ANDROID_LOG_NONBLOCK) { 816 /* Deal with an unresponsive logd */ 817 sigaction(SIGALRM, &ignore, &old_sigaction); 818 old_alarm = alarm(30); 819 } 820 ret = write(sock, buffer, cp - buffer); 821 e = errno; 822 if (logger_list->mode & ANDROID_LOG_NONBLOCK) { 823 if (e == EINTR) { 824 e = ETIMEDOUT; 825 } 826 alarm(old_alarm); 827 sigaction(SIGALRM, &old_sigaction, NULL); 828 } 829 830 if (ret <= 0) { 831 close(sock); 832 if ((ret == -1) && e) { 833 return -e; 834 } 835 if (ret == 0) { 836 return -EIO; 837 } 838 return ret; 839 } 840 841 logger_list->sock = sock; 842 } 843 844 ret = 0; 845 while(1) { 846 memset(log_msg, 0, sizeof(*log_msg)); 847 848 if (logger_list->mode & ANDROID_LOG_NONBLOCK) { 849 /* particularily useful if tombstone is reporting for logd */ 850 sigaction(SIGALRM, &ignore, &old_sigaction); 851 old_alarm = alarm(30); 852 } 853 /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */ 854 ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0); 855 e = errno; 856 if (logger_list->mode & ANDROID_LOG_NONBLOCK) { 857 if ((ret == 0) || (e == EINTR)) { 858 e = EAGAIN; 859 ret = -1; 860 } 861 alarm(old_alarm); 862 sigaction(SIGALRM, &old_sigaction, NULL); 863 } 864 865 if (ret <= 0) { 866 if ((ret == -1) && e) { 867 return -e; 868 } 869 return ret; 870 } 871 872 logger_for_each(logger, logger_list) { 873 if (log_msg->entry.lid == logger->id) { 874 return ret; 875 } 876 } 877 } 878 /* NOTREACH */ 879 return ret; 880} 881 882/* Close all the logs */ 883void android_logger_list_free(struct logger_list *logger_list) 884{ 885 if (logger_list == NULL) { 886 return; 887 } 888 889 while (!list_empty(&logger_list->node)) { 890 struct listnode *node = list_head(&logger_list->node); 891 struct logger *logger = node_to_item(node, struct logger, node); 892 android_logger_free(logger); 893 } 894 895 if (logger_list->sock >= 0) { 896 close (logger_list->sock); 897 } 898 899 free(logger_list); 900} 901