1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <errno.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10
11#include <zircon/syscalls.h>
12#include <zircon/syscalls/log.h>
13
14void usage(void) {
15    fprintf(stderr,
16        "usage: dlog        dump the zircon debug log\n"
17        "\n"
18        "options: -f        don't exit, keep waiting for new messages\n"
19        "         -p <pid>  only show messages from specified pid\n"
20        "         -t        only show the text of messages (no metadata)\n"
21        "         -h        show help\n"
22        );
23}
24
25int main(int argc, char** argv) {
26    bool tail = false;
27    bool filter_pid = false;
28    bool plain = false;
29    zx_koid_t pid = 0;
30    zx_handle_t h;
31
32    while (argc > 1) {
33        if (!strcmp(argv[1], "-h")) {
34            usage();
35            return 0;
36        } else if (!strcmp(argv[1], "-f")) {
37            tail = true;
38        } else if (!strcmp(argv[1], "-t")) {
39            plain = true;
40        } else if (!strcmp(argv[1], "-p")) {
41            argc--;
42            argv++;
43            if (argc < 2) {
44                usage();
45                return -1;
46            }
47            errno = 0;
48            pid = strtoull(argv[1], NULL, 0);
49            if (errno) {
50                fprintf(stderr, "dlog: invalid pid\n");
51                return -1;
52            }
53            filter_pid = true;
54        } else {
55            usage();
56            return -1;
57        }
58        argc--;
59        argv++;
60    }
61
62    if (zx_debuglog_create(ZX_HANDLE_INVALID, ZX_LOG_FLAG_READABLE, &h) < 0) {
63        fprintf(stderr, "dlog: cannot open debug log\n");
64        return -1;
65    }
66
67    char buf[ZX_LOG_RECORD_MAX];
68    zx_log_record_t* rec = (zx_log_record_t*)buf;
69    for (;;) {
70        zx_status_t status;
71        if ((status = zx_debuglog_read(h, 0, rec, ZX_LOG_RECORD_MAX)) < 0) {
72            if ((status == ZX_ERR_SHOULD_WAIT) && tail) {
73                zx_object_wait_one(h, ZX_LOG_READABLE, ZX_TIME_INFINITE, NULL);
74                continue;
75            }
76            break;
77        }
78        if (filter_pid && (pid != rec->pid)) {
79            continue;
80        }
81        if (!plain) {
82            char tmp[32];
83            size_t len = snprintf(tmp, sizeof(tmp), "[%05d.%03d] ",
84                                  (int)(rec->timestamp / 1000000000ULL),
85                                  (int)((rec->timestamp / 1000000ULL) % 1000ULL));
86            write(1, tmp, (len > sizeof(tmp) ? sizeof(tmp) : len));
87        }
88        write(1, rec->data, rec->datalen);
89        if ((rec->datalen == 0) || (rec->data[rec->datalen - 1] != '\n')) {
90            write(1, "\n", 1);
91        }
92    }
93    return 0;
94}
95