1 #include "log_buffer.h"
2 #include "logger_internal.h"
6 * @brief Append to buffer
7 * @details Appends an entry to the buffer
8 * @param[in] s The logger server
9 * @param[in] entry The entry to append
10 * @param[in] b The buffer whither to append
12 int buffer_append(const dlogutil_entry_s *entry, struct log_buffer *b)
14 if (!log_storage_add_new_entry(b->log_storage_ptr, entry))
20 * @brief Service pipe log data
21 * @details Handle log messages incoming through a pipe
22 * @param[in] server The logger server
23 * @param[in] wr The writer who sent the logs
24 * @param[in] event The event associated with the data
25 * @return 0 on success, else -errno
27 static int service_writer_pipe(struct logger *server, struct writer *wr, struct epoll_event *event)
29 if (event->events & EPOLLIN) {
30 int r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
32 if (r == -1 && errno == EAGAIN)
34 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
41 struct pipe_logger_entry *const ple = (struct pipe_logger_entry *const)wr->buffer;
42 while ((wr->readed >= sizeof(ple->len)) && (ple->len <= wr->readed)) {
43 const int payload_size = ple->len - sizeof *ple;
44 if (payload_size < 0 || payload_size > LOG_MAX_PAYLOAD_SIZE)
47 struct dlogutil_entry_with_msg lem;
48 parse_pipe_message(ple, &lem.header, ple->len);
49 add_recv_timestamp(&lem.header, server->time);
50 fixup_pipe_msg(&lem, payload_size);
51 if (qos_is_enabled(&server->qos))
52 qos_add_log(&server->qos, &lem.header);
53 r = buffer_append(&lem.header, wr->buf_ptr);
54 wr->readed -= ple->len;
55 memmove(wr->buffer, wr->buffer + ple->len, sizeof wr->buffer - ple->len);
60 } else if (event->events & EPOLLHUP)
67 * @brief Service util request
68 * @details Handle a request from util
69 * @param[in] server The logger server
70 * @param[in] wr The writer who sent the request
71 * @param[in] msg The message containing the request
72 * @return 0 on success, else -errno
74 static int service_writer_handle_req_util(struct logger* server, struct writer* wr, struct dlog_control_msg* msg)
80 // check request type, that should be always DLOG_REQ_HANDLE_LOGUTIL
81 // as dispatched by service_writer_handle_req_ctrl handler
82 // don't assert for compatibility with service_writer_handle_req_pipe
83 // and possible mistakes in the future that would be hard to track
84 if (msg->request != DLOG_REQ_HANDLE_LOGUTIL)
87 if (msg->length <= sizeof(struct dlog_control_msg) ||
88 msg->length > sizeof(struct dlog_control_msg) + MAX_LOGGER_REQUEST_LEN)
91 if (msg->data[msg->length - sizeof(struct dlog_control_msg)] != 0)
94 __attribute__((cleanup(reader_pipe_cleanup))) struct reader_pipe *reader = NULL;
97 __attribute__((cleanup(free_dlogutil_line_params))) struct dlogutil_line_params params;
98 if (!initialize_dlogutil_line_params(¶ms, (struct buf_params) { })) {
103 retval = get_dlogutil_line_params(msg->data, ¶ms);
109 if (params.file_path) {
110 /* Do not trust writer-based readers (only config-based).
111 * The control socket's privilege checks are fairly lenient
112 * so this prevents people from asking us to overwrite
113 * some potentially important files at logger privilege.
115 * At some point it would be good to be able to skip the
116 * middleman and become able to write to a file directly
117 * though. The daemon should become able to receive an
118 * opened file descriptor from a writer. */
123 retval = reader_pipe_init_with_writer(&reader, wr, server, params.filter, ¶ms.file, params.monitor, params.is_dumping);
127 int write_fd = -1, read_fd = -1;
128 retval = create_fifo_fds(server, wr->fd_entity.fd, &write_fd, &read_fd, reader->is_dumping);
132 set_write_fd_entity(&reader->common.fd_entity_sink, write_fd);
133 retval = send_pipe(wr->fd_entity.fd, read_fd);
139 retval = add_reader_pipe(server, reader);
147 retval = send_dlog_reply(wr->fd_entity.fd, DLOG_REQ_HANDLE_LOGUTIL, DLOG_REQ_RESULT_ERR, NULL, 0);
149 printf("ERROR: both create_reader_from_dlogutil_line() and send_dlog_reply() failed\n");
154 static int service_writer_handle_req_get_usage(struct logger *server, struct writer *wr, struct dlog_control_msg *msg)
159 assert(msg->request == DLOG_REQ_GET_USAGE);
161 uint32_t buf_size = log_storage_get_usage(wr->buf_ptr->log_storage_ptr);
163 return send_dlog_reply(wr->fd_entity.fd, DLOG_REQ_GET_USAGE, DLOG_REQ_RESULT_OK, &buf_size, sizeof buf_size);
166 static int service_writer_handle_req_get_capacity(struct logger *server, struct writer *wr, struct dlog_control_msg *msg)
171 assert(msg->request == DLOG_REQ_GET_CAPACITY);
173 uint32_t buf_size = log_storage_get_capacity(wr->buf_ptr->log_storage_ptr);
175 return send_dlog_reply(wr->fd_entity.fd, DLOG_REQ_GET_CAPACITY, DLOG_REQ_RESULT_OK, &buf_size, sizeof buf_size);
179 * @brief Service clear request
180 * @details Handle a clear-buffer request
181 * @param[in] server The logger server
182 * @param[in] wr The writer who sent the request
183 * @param[in] msg The message containing the request
184 * @return 0 on success, else -errno
186 static int service_writer_handle_req_clear(struct logger* server, struct writer* wr, struct dlog_control_msg* msg)
191 // check request type, that should be always DLOG_REQ_CLEAR
192 // as dispatched by service_writer_handle_req_ctrl handler
193 // don't assert for compatibility with service_writer_handle_req_pipe
194 // and possible mistakes in the future that would be hard to track
195 if (msg->request != DLOG_REQ_CLEAR)
198 if (msg->length != (sizeof(struct dlog_control_msg)))
201 if (!wr || !wr->buf_ptr)
204 log_storage_clear(wr->buf_ptr->log_storage_ptr);
210 * @brief Service control request
211 * @details Handle a clear-buffer or util request in respect to msg request type
212 * @param[in] server The logger server
213 * @param[in] wr The writer who sent the request
214 * @param[in] msg The message containing the request
215 * @return 0 on success, else -errno
217 static int service_writer_handle_req_ctrl(struct logger *server, struct writer *wr, struct dlog_control_msg *msg)
224 switch (msg->request) {
225 case DLOG_REQ_CLEAR: ret = service_writer_handle_req_clear (server, wr, msg); break;
226 case DLOG_REQ_HANDLE_LOGUTIL: ret = service_writer_handle_req_util (server, wr, msg); break;
227 case DLOG_REQ_GET_CAPACITY: ret = service_writer_handle_req_get_capacity(server, wr, msg); break;
228 case DLOG_REQ_GET_USAGE: ret = service_writer_handle_req_get_usage (server, wr, msg); break;
230 default: ret = -EINVAL;
233 if (wr->readed > msg->length) {
234 wr->readed -= msg->length;
235 memmove(wr->buffer, wr->buffer + msg->length, wr->readed);
243 * @brief Service a pipe acquisition request
244 * @details Handle a pipe request
245 * @param[in] server The logger server
246 * @param[in] wr The writer who sent the request
247 * @param[in] msg The message containing the request
248 * @return 0 on success, else -errno
250 static int service_writer_handle_req_pipe(struct logger* server, struct writer* wr, struct dlog_control_msg* msg)
256 // check request type given by user
257 // don't assert that as the message is not parsed before
258 if (msg->request != DLOG_REQ_PIPE)
261 if (msg->length != sizeof(struct dlog_control_msg))
265 if (pipe2(pipe_fd, O_CLOEXEC | O_NONBLOCK) < 0) { // O_NONBLOCK just for pipe_fd[0]; writer removes it for pipe_fd[1] on its own
266 check_if_fd_limit_reached(server, errno);
270 if (fcntl(pipe_fd[1], F_SETPIPE_SZ, PIPE_REQUESTED_SIZE) < 0) {
271 /* Ignore failures. This call is just a performance optimisation
272 * and doesn't affect functionality; we can't do anything about
273 * an error anyway. */
279 struct fd_entity pipe_entity = wr->fd_entity;
280 set_read_fd_entity(&pipe_entity, pipe_fd[0]);
281 r = add_fd_entity(&server->epoll_common, &pipe_entity);
285 r = send_pipe(wr->fd_entity.fd, pipe_fd[1]);
290 writer_close_fd(server, wr);
291 wr->service_writer = service_writer_pipe;
292 wr->fd_entity = pipe_entity;
297 remove_fd_entity(&server->epoll_common, &pipe_entity);
307 * @brief Create buffer
308 * @details Allocate a buffer structure
309 * @param[out] lb The newly-allocated buffer
310 * @param[in] buf_id The buffer ID
311 * @param[in] data Buffer config data
312 * @return 0 on success, -errno on failure
314 int buffer_create(struct log_buffer **log_buffer, log_id_t buf_id, struct buffer_config_data *data)
317 struct log_buffer *lb = (struct log_buffer *) calloc(1, sizeof(*lb));
323 lb->log_storage_ptr = log_storage_create(data->size, data->sort_by);
324 if (!lb->log_storage_ptr) {
330 r = socket_initialize(&lb->sock_ctl, lb, service_writer_handle_req_ctrl, &data->ctl_socket);
332 log_storage_free(lb->log_storage_ptr);
337 r = socket_initialize(&lb->sock_wr, lb, service_writer_handle_req_pipe, &data->write_socket);
339 socket_close(&lb->sock_ctl);
340 log_storage_free(lb->log_storage_ptr);
349 static bool cond_reader_pipe_free(void *ptr, void *user_data)
351 struct reader_pipe *reader = (struct reader_pipe *)ptr;
352 struct logger *logger = (struct logger *)user_data;
354 // TODO: This is absurd, why isn't this in the reader_pipe_free function?
355 if (reader->common.fd_entity_sink.fd >= 0)
356 remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink);
357 if (reader->common.fd_entity_source.fd >= 0)
358 remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_source);
359 reader_pipe_free(reader);
365 * @details Deallocate a buffer
366 * @param[in] buffer The buffer to deallocate
367 * @param[in] logger The server to remove buffer readers from fd loop
369 void buffer_free(struct log_buffer *buffer, struct logger *logger)
373 list_remove_if(&buffer->readers_pipe, logger, cond_reader_pipe_free);
375 socket_close(&buffer->sock_ctl);
376 socket_close(&buffer->sock_wr);
378 log_storage_free(buffer->log_storage_ptr);