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