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/logger/logger.h>
6
7 #include <fbl/string_buffer.h>
8 #include <fuchsia/logger/c/fidl.h>
9 #include <lib/fidl/cpp/message_buffer.h>
10 #include <lib/zx/channel.h>
11 #include <stdint.h>
12 #include <lib/syslog/logger.h>
13 #include <lib/syslog/wire_format.h>
14 #include <zircon/processargs.h>
15 #include <zircon/status.h>
16
17 #include <utility>
18
19 namespace logger {
20 namespace {
21
22 static fx_log_packet_t packet;
23
24 } // namespace
25
LoggerImpl(zx::channel channel,int out_fd)26 LoggerImpl::LoggerImpl(zx::channel channel, int out_fd)
27 : channel_(std::move(channel)),
28 fd_(out_fd),
29 wait_(this, channel_.get(), ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED),
30 socket_wait_(this) {
31 }
32
~LoggerImpl()33 LoggerImpl::~LoggerImpl() {
34 fsync(fd_);
35 }
36
Begin(async_dispatcher_t * dispatcher)37 zx_status_t LoggerImpl::Begin(async_dispatcher_t* dispatcher) {
38 return wait_.Begin(dispatcher);
39 }
40
PrintLogMessage(const fx_log_packet_t * packet)41 zx_status_t LoggerImpl::PrintLogMessage(const fx_log_packet_t* packet) {
42 fbl::StringBuffer<sizeof(fx_log_packet_t) + 100> buf; // should be enough to log message
43 buf.AppendPrintf("[%05ld.%06ld]", packet->metadata.time / 1000000000UL, (packet->metadata.time / 1000UL) % 1000000UL);
44 buf.AppendPrintf("[%ld]", packet->metadata.pid);
45 buf.AppendPrintf("[%ld]", packet->metadata.tid);
46
47 // print tags
48 size_t pos = 0;
49 buf.Append("[");
50 unsigned int tag_len = packet->data[pos];
51 int i = 1;
52 while (tag_len > 0) {
53 if (i > FX_LOG_MAX_TAGS || tag_len > FX_LOG_MAX_TAG_LEN) {
54 return ZX_ERR_INVALID_ARGS;
55 }
56 if (i > 1) {
57 buf.Append(", ");
58 }
59 pos = pos + 1;
60 buf.Append(packet->data + pos, tag_len);
61 pos = pos + tag_len;
62 tag_len = packet->data[pos];
63 i++;
64 }
65 buf.Append("]");
66
67 auto severity = packet->metadata.severity;
68 switch (severity) {
69 case FX_LOG_INFO:
70 buf.Append(" INFO");
71 break;
72 case FX_LOG_WARNING:
73 buf.Append(" WARNING");
74 break;
75 case FX_LOG_ERROR:
76 buf.Append(" ERROR");
77 break;
78 case FX_LOG_FATAL:
79 buf.Append(" FATAL");
80 break;
81 default:
82 buf.AppendPrintf(" VLOG(%d)", -severity);
83 }
84 buf.Append(": ");
85 pos++; //point to log msg
86 buf.Append(packet->data + pos);
87 buf.Append("\n");
88
89 ssize_t status = write(fd_, buf.data(), buf.size());
90 if (status < 0) {
91 return ZX_ERR_IO;
92 }
93 return ZX_OK;
94 }
95
OnLogMessage(async_dispatcher_t * dispatcher,async::WaitBase * wait,zx_status_t status,const zx_packet_signal_t * signal)96 void LoggerImpl::OnLogMessage(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
97 const zx_packet_signal_t* signal) {
98 if (status != ZX_OK) {
99 NotifyError(status);
100 return;
101 }
102
103 if (signal->observed & ZX_SOCKET_READABLE) {
104 memset(&packet, 0, sizeof(packet));
105 status = socket_.read(0, &packet, sizeof(packet), nullptr);
106 if (status != ZX_OK) {
107 NotifyError(status);
108 return;
109 }
110 if (status != ZX_ERR_SHOULD_WAIT) {
111 // set last byte of packet to zero so that we don't overflow buffer while
112 // reading message.
113 packet.data[sizeof(packet.data) - 1] = 0;
114 status = PrintLogMessage(&packet);
115 if (status == ZX_ERR_INVALID_ARGS) {
116 NotifyError(status);
117 return;
118 }
119 }
120 status = wait->Begin(dispatcher);
121 if (status != ZX_OK) {
122 NotifyError(status);
123 }
124 return;
125 }
126
127 ZX_DEBUG_ASSERT(signal->observed & ZX_SOCKET_PEER_CLOSED);
128 NotifyError(ZX_ERR_PEER_CLOSED);
129 }
130
OnHandleReady(async_dispatcher_t * dispatcher,async::WaitBase * wait,zx_status_t status,const zx_packet_signal_t * signal)131 void LoggerImpl::OnHandleReady(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
132 const zx_packet_signal_t* signal) {
133 if (status != ZX_OK) {
134 NotifyError(status);
135 return;
136 }
137
138 if (signal->observed & ZX_CHANNEL_READABLE) {
139 fidl::MessageBuffer buffer;
140 for (uint64_t i = 0; i < signal->count; i++) {
141 status = ReadAndDispatchMessage(&buffer, dispatcher);
142 if (status == ZX_ERR_SHOULD_WAIT)
143 break;
144 if (status != ZX_OK) {
145 NotifyError(status);
146 return;
147 }
148 }
149 status = wait->Begin(dispatcher);
150 if (status != ZX_OK) {
151 NotifyError(status);
152 }
153 return;
154 }
155
156 ZX_DEBUG_ASSERT(signal->observed & ZX_CHANNEL_PEER_CLOSED);
157 channel_.reset();
158 if (!socket_) {
159 // if there is no socket, it doesn't make sense to keep running this
160 // instance.
161 NotifyError(ZX_ERR_PEER_CLOSED);
162 }
163 }
164
ReadAndDispatchMessage(fidl::MessageBuffer * buffer,async_dispatcher_t * dispatcher)165 zx_status_t LoggerImpl::ReadAndDispatchMessage(fidl::MessageBuffer* buffer, async_dispatcher_t* dispatcher) {
166 fidl::Message message = buffer->CreateEmptyMessage();
167 zx_status_t status = message.Read(channel_.get(), 0);
168 if (status != ZX_OK)
169 return status;
170 if (!message.has_header())
171 return ZX_ERR_INVALID_ARGS;
172 switch (message.ordinal()) {
173 case fuchsia_logger_LogSinkConnectOrdinal:
174 return Connect(std::move(message), dispatcher);
175 default:
176 fprintf(stderr, "logger: error: Unknown message ordinal: %d\n", message.ordinal());
177 return ZX_ERR_NOT_SUPPORTED;
178 }
179 }
180
Connect(fidl::Message message,async_dispatcher_t * dispatcher)181 zx_status_t LoggerImpl::Connect(fidl::Message message, async_dispatcher_t* dispatcher) {
182 if (socket_) {
183 return ZX_ERR_INVALID_ARGS;
184 }
185 const char* error_msg = nullptr;
186 zx_status_t status = message.Decode(&fuchsia_logger_LogSinkConnectRequestTable, &error_msg);
187 if (status != ZX_OK) {
188 fprintf(stderr, "logger: error: Connect: %s\n", error_msg);
189 return status;
190 }
191 auto* request = message.GetBytesAs<fuchsia_logger_LogSinkConnectRequest>();
192 socket_.reset(request->socket);
193 socket_wait_.set_object(socket_.get());
194 socket_wait_.set_trigger(ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED);
195 socket_wait_.Begin(dispatcher);
196 return ZX_OK;
197 }
198
NotifyError(zx_status_t error)199 void LoggerImpl::NotifyError(zx_status_t error) {
200 socket_wait_.Cancel();
201 wait_.Cancel();
202 channel_.reset();
203 socket_.reset();
204 if (error_handler_)
205 error_handler_(error);
206 }
207
208 } // namespace logger
209