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