1117397Skan// Copyright 2016 The Fuchsia Authors. All rights reserved.
2117397Skan// Use of this source code is governed by a BSD-style license that can be
3169691Skan// found in the LICENSE file.
4169691Skan
5117397Skan#include <errno.h>
6117397Skan#include <stdio.h>
7117397Skan#include <stdlib.h>
8117397Skan#include <string.h>
9117397Skan#include <unistd.h>
10117397Skan
11117397Skan#include <zircon/syscalls.h>
12117397Skan#include <zircon/syscalls/log.h>
13117397Skan
14117397Skanvoid usage(void) {
15117397Skan    fprintf(stderr,
16117397Skan        "usage: dlog        dump the zircon debug log\n"
17117397Skan        "\n"
18117397Skan        "options: -f        don't exit, keep waiting for new messages\n"
19169691Skan        "         -p <pid>  only show messages from specified pid\n"
20117397Skan        "         -t        only show the text of messages (no metadata)\n"
21117397Skan        "         -h        show help\n"
22117397Skan        );
23117397Skan}
24117397Skan
25117397Skanint main(int argc, char** argv) {
26117397Skan    bool tail = false;
27117397Skan    bool filter_pid = false;
28117397Skan    bool plain = false;
29117397Skan    zx_koid_t pid = 0;
30117397Skan    zx_handle_t h;
31169691Skan
32117397Skan    while (argc > 1) {
33169691Skan        if (!strcmp(argv[1], "-h")) {
34169691Skan            usage();
35117397Skan            return 0;
36132720Skan        } else if (!strcmp(argv[1], "-f")) {
37132720Skan            tail = true;
38132720Skan        } else if (!strcmp(argv[1], "-t")) {
39132720Skan            plain = true;
40132720Skan        } else if (!strcmp(argv[1], "-p")) {
41132720Skan            argc--;
42117397Skan            argv++;
43132720Skan            if (argc < 2) {
44132720Skan                usage();
45132720Skan                return -1;
46132720Skan            }
47132720Skan            errno = 0;
48132720Skan            pid = strtoull(argv[1], NULL, 0);
49132720Skan            if (errno) {
50132720Skan                fprintf(stderr, "dlog: invalid pid\n");
51132720Skan                return -1;
52132720Skan            }
53132720Skan            filter_pid = true;
54132720Skan        } else {
55132720Skan            usage();
56132720Skan            return -1;
57132720Skan        }
58132720Skan        argc--;
59132720Skan        argv++;
60132720Skan    }
61132720Skan
62132720Skan    if (zx_debuglog_create(ZX_HANDLE_INVALID, ZX_LOG_FLAG_READABLE, &h) < 0) {
63132720Skan        fprintf(stderr, "dlog: cannot open debug log\n");
64132720Skan        return -1;
65132720Skan    }
66132720Skan
67132720Skan    char buf[ZX_LOG_RECORD_MAX];
68132720Skan    zx_log_record_t* rec = (zx_log_record_t*)buf;
69132720Skan    for (;;) {
70132720Skan        zx_status_t status;
71117397Skan        if ((status = zx_debuglog_read(h, 0, rec, ZX_LOG_RECORD_MAX)) < 0) {
72117397Skan            if ((status == ZX_ERR_SHOULD_WAIT) && tail) {
73132720Skan                zx_object_wait_one(h, ZX_LOG_READABLE, ZX_TIME_INFINITE, NULL);
74132720Skan                continue;
75132720Skan            }
76132720Skan            break;
77132720Skan        }
78117397Skan        if (filter_pid && (pid != rec->pid)) {
79132720Skan            continue;
80132720Skan        }
81132720Skan        if (!plain) {
82132720Skan            char tmp[32];
83132720Skan            size_t len = snprintf(tmp, sizeof(tmp), "[%05d.%03d] ",
84132720Skan                                  (int)(rec->timestamp / 1000000000ULL),
85132720Skan                                  (int)((rec->timestamp / 1000000ULL) % 1000ULL));
86132720Skan            write(1, tmp, (len > sizeof(tmp) ? sizeof(tmp) : len));
87132720Skan        }
88132720Skan        write(1, rec->data, rec->datalen);
89132720Skan        if ((rec->datalen == 0) || (rec->data[rec->datalen - 1] != '\n')) {
90132720Skan            write(1, "\n", 1);
91132720Skan        }
92132720Skan    }
93132720Skan    return 0;
94132720Skan}
95132720Skan