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