1 // Copyright 2018 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 <lib/zxio/inception.h>
6 #include <lib/zxio/null.h>
7 #include <lib/zxio/ops.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <zircon/syscalls.h>
11 #include <zircon/syscalls/log.h>
12 
13 #define LOGBUF_MAX (ZX_LOG_RECORD_MAX - sizeof(zx_log_record_t))
14 
15 struct zxio_debuglog_buffer {
16     unsigned next;
17     char pending[LOGBUF_MAX];
18 };
19 
zxio_debuglog_close(zxio_t * io)20 static zx_status_t zxio_debuglog_close(zxio_t* io) {
21     zxio_debuglog_t* debuglog = reinterpret_cast<zxio_debuglog_t*>(io);
22     zx_handle_t handle = debuglog->handle;
23     debuglog->handle = ZX_HANDLE_INVALID;
24     zx_handle_close(handle);
25     if (debuglog->buffer != nullptr) {
26         free(debuglog->buffer);
27         debuglog->buffer = nullptr;
28     }
29     return ZX_OK;
30 }
31 
zxio_debuglog_write(zxio_t * io,const void * buffer,size_t capacity,size_t * out_actual)32 static zx_status_t zxio_debuglog_write(zxio_t* io, const void* buffer, size_t capacity,
33                                        size_t* out_actual) {
34     zxio_debuglog_t* debuglog = reinterpret_cast<zxio_debuglog_t*>(io);
35 
36     if (debuglog->buffer == nullptr) {
37         debuglog->buffer = static_cast<zxio_debuglog_buffer_t*>(
38             calloc(1, sizeof(*debuglog->buffer)));
39         if (debuglog->buffer == nullptr) {
40             *out_actual = capacity;
41             return ZX_OK;
42         }
43     }
44 
45     zxio_debuglog_buffer_t* outgoing = debuglog->buffer;
46     const uint8_t* data = static_cast<const uint8_t*>(buffer);
47     size_t n = capacity;
48     while (n-- > 0u) {
49         char c = *data++;
50         if (c == '\n') {
51             zx_debuglog_write(debuglog->handle, 0u, outgoing->pending,
52                               outgoing->next);
53             outgoing->next = 0u;
54             continue;
55         }
56         if (c < ' ') {
57             continue;
58         }
59         outgoing->pending[outgoing->next++] = c;
60         if (outgoing->next == LOGBUF_MAX) {
61             zx_debuglog_write(debuglog->handle, 0u, outgoing->pending,
62                               outgoing->next);
63             outgoing->next = 0u;
64             continue;
65         }
66     }
67     *out_actual = capacity;
68     return ZX_OK;
69 }
70 
__anon57eaef0d0102() 71 static constexpr zxio_ops_t zxio_debuglog_ops = ([]() {
72     zxio_ops_t ops = zxio_default_ops;
73     ops.close = zxio_debuglog_close;
74     ops.write = zxio_debuglog_write;
75     return ops;
76 })();
77 
zxio_debuglog_init(zxio_storage_t * storage,zx_handle_t handle)78 zx_status_t zxio_debuglog_init(zxio_storage_t* storage, zx_handle_t handle) {
79     zxio_debuglog_t* debuglog = reinterpret_cast<zxio_debuglog_t*>(storage);
80     zxio_init(&debuglog->io, &zxio_debuglog_ops);
81     debuglog->handle = handle;
82     debuglog->buffer = nullptr;
83     return ZX_OK;
84 }
85