2 * Copyright (c) 2016, Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include "logger_internal.h"
24 #include <dynamic_config.h>
25 #include <qos_defaults.h>
28 * @addtogroup DLOG_IMPLEMENTATION
30 * @defgroup DLOG_LOGGER Logger
31 * @brief Logger daemon
32 * @details The logger is the core component of the logging framework. It is responsible for collecting, processing and exposing logs.
36 // function prototypes
37 static void logger_free(struct logger* l);
38 static int initialize_epoll_size(struct epoll_event **events, unsigned *size);
40 /** global state when logger is not interrupted by any handled signals */
41 static volatile sig_atomic_t g_logger_run = 1;
43 static const int DEFAULT_EPOLL_TIME_MS = 1000;
45 static const int DEFAULT_LAZY_POLLING_TOTAL_MS = 0;
46 static const int DEFAULT_LAZY_POLLING_SLEEP_MS = 1000;
48 static const int S_TO_MS = 1000;
49 static const int MS_TO_NS = 1000000;
51 struct backend_data g_backend = {};
54 * @brief Parse permissions
55 * @details Parse a string representation of permissions to the internal integral one
56 * @param[in] str The string representation
57 * @return The integer representation
59 int parse_permissions(const char * str)
65 return S_IWUSR | S_IWGRP | S_IWOTH; // 0222: everyone can write
67 parsed = strtol(str, & parse_safety, 8); // note, rights are octal
68 if (parse_safety != (str + strlen(str)))
73 // note that R and X are pretty useless, only W makes sense
74 if (parsed & 00001) ret |= S_IXOTH;
75 if (parsed & 00002) ret |= S_IWOTH;
76 if (parsed & 00004) ret |= S_IROTH;
77 if (parsed & 00010) ret |= S_IXGRP;
78 if (parsed & 00020) ret |= S_IWGRP;
79 if (parsed & 00040) ret |= S_IRGRP;
80 if (parsed & 00100) ret |= S_IXUSR;
81 if (parsed & 00200) ret |= S_IWUSR;
82 if (parsed & 00400) ret |= S_IRUSR;
83 if (parsed & 01000) ret |= S_ISVTX;
84 if (parsed & 02000) ret |= S_ISGID;
85 if (parsed & 04000) ret |= S_ISUID;
88 printf("Warning: useless bits in permissions %s!", str);
94 * @brief Get numerical ids for specified user and group
95 * @details Converts user and group strings to proper uid and gid identifiers
96 * @param[in] user The new user
97 * @param[in] group The new group
98 * @param[out] uid The uid for user
99 * @param[out] gid The numerical gid for group
100 * @return 0 on success, else -errno
102 int usergr2id(const char * user, const char * group, uid_t *uid, gid_t *gid)
104 struct passwd pwd, *ppwd;
105 struct group grp, *pgrp;
106 int bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
114 char *const buffer = (char *)alloca(bufsize);
116 if (getgrnam_r(user, &grp, buffer, bufsize, &pgrp))
121 if (getpwnam_r(group, &pwd, buffer, bufsize, &ppwd))
133 * @brief Reset privileges
134 * @details Resets privileges to those specified at build-time
135 * @return 0 on success, else -errno
137 int reset_self_privileges()
143 r = usergr2id(DLOG_SERVER_USER, DLOG_SERVER_GROUP, &uid, &gid);
147 if (getegid() != gid && setgid(gid) < 0)
149 if (geteuid() != uid && setuid(uid) < 0)
150 return -errno; // should never happen
155 static bool cond_reader_logger_free(void *ptr, void *user_data)
157 struct reader_logger *reader = (struct reader_logger *)ptr;
158 struct logger *logger = (struct logger *)user_data;
160 // TODO: This is absurd, why isn't this in the reader_logger_free function?
161 if (reader->common.fd_entity_sink.fd >= 0)
162 remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink);
163 if (reader->common.fd_entity_source.fd >= 0)
164 remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_source);
165 reader_logger_free(reader);
169 void qos_periodic_check(struct logger *server)
171 struct qos_module *const qos = &server->qos;
172 struct timespec const now = server->time.mono;
174 if (now.tv_sec < qos->cancel_limits_at.tv_sec)
176 if (now.tv_sec == qos->cancel_limits_at.tv_sec
177 && now.tv_nsec < qos->cancel_limits_at.tv_nsec)
180 if (metrics_get_total(qos->log_metrics) >= qos->threshold)
181 qos_apply_limits(qos);
183 qos_relax_limits(qos);
185 qos_set_next_update_time(qos, now);
186 metrics_clear(qos->log_metrics);
190 * @brief FD limit handler
191 * @details Checks whether the FD limit was reached and leaves logs about it if so
192 * @param[in] server The logger server
193 * @param[in] err errno from the call that failed to create an FD
195 void check_if_fd_limit_reached(struct logger *server, int err)
199 if (err != ENFILE && err != EMFILE)
202 printf("ERROR: dlog_logger fd limit reached!\n");
204 /* pick one representative buffer to send the log to;
205 * no point spamming all the buffers, especially since
206 * default dlogutil invocations display 3 buffers so
207 * it would appear multiple times */
208 struct log_buffer *const buf = server->buffers[LOG_ID_MAIN];
212 struct dlogutil_entry_with_msg entry;
213 create_pipe_message(&entry,
214 DLOG_FATAL, /* not really FATAL, but since we're at the FD limit
215 * there are thousands of logging programs so this one
216 * would likely get lost in the flood since developers
217 * tend to overuse ERROR (and FATAL is the one above) */
219 "\x1b[31m DLOG DAEMON FD LIMIT REACHED \x1b[0m" // make it stand out
221 set_pipe_message_sent_timestamp((struct pipe_logger_entry *) &entry, &server->time.mono, &server->time.real);
223 if (buffer_append(&entry.header, buf))
224 printf("ERROR: not enough memory either, please check platform settings as the daemon is seriously resource-starved!\n");
227 void reader_notify_losing_log(const dlogutil_entry_s *le, void *reader_)
229 struct reader_pipe *reader = (struct reader_pipe *) reader_;
232 reader_print_out_single_log(reader, (dlogutil_entry_s *)le);
236 * @brief Add reader to log buffer
237 * @details Adds a reader to the log buffers reader list
238 * @param[in] log_buffer The buffer whither to add the reader
239 * @param[in] reader The reader to add to the buffer
240 * @return 0 on success, -ENOMEM on memory allocation error
242 int add_buffer_reader(struct log_buffer *buffer, struct reader_pipe *reader)
247 reader->log_storage_reader_ptr = log_storage_new_reader(buffer->log_storage_ptr,
248 reader->is_dumping, reader->monitor, reader_notify_losing_log, reader);
250 if (!reader->log_storage_reader_ptr)
253 return list_add(&buffer->readers_pipe, reader) ? 0 : -ENOMEM;
256 int add_reader_pipe(struct logger *server, struct reader_pipe *reader)
261 if (reader->common.fd_entity_sink.fd >= 0) {
262 /* Readers who write to file have no sink FD entity (or, strictly
263 * speaking, they do have one but it is not filled) since a file
264 * is not eligible to be added to epoll. However, the entity primarily
265 * serves to handle pipes getting clogged mid-write (which cannot
266 * happen for files) and is not involved in starting a write,
267 * which is handled by the source FD entity, not sink (and which is
268 * also done periodically for all readers anyway regardless
269 * of whether they've been added to epoll or not). The other use
270 * case for epoll - the one where connection FDs leak for unused
271 * buffers - is not a problem here because the daemon is not
272 * supposed to ever stop writing to files. */
274 int r = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
280 ret = add_buffer_reader(reader->buf_ptr, reader);
281 if (ret < 0 && reader->common.fd_entity_sink.fd >= 0)
282 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
287 static int add_reader_logger(struct logger *server, struct reader_logger *reader)
292 if (reader->common.fd_entity_sink.fd >= 0) {
293 /* Readers who write to file have no sink FD entity (or, strictly
294 * speaking, they do have one but it is not filled) since a file
295 * is not eligible to be added to epoll. However, the entity primarily
296 * serves to handle pipes getting clogged mid-write (which cannot
297 * happen for files) and is not involved in starting a write,
298 * which is handled by the source FD entity, not sink (and which is
299 * also done periodically for all readers anyway regardless
300 * of whether they've been added to epoll or not). The other use
301 * case for epoll - the one where connection FDs leak for unused
302 * buffers - is not a problem here because the daemon is not
303 * supposed to ever stop writing to files. */
305 int r = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
312 assert(reader->common.fd_entity_source.fd >= 0);
313 ret = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_source);
317 if (!list_add(&server->readers_logger, reader)) {
318 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_source);
326 if (reader->common.fd_entity_sink.fd >= 0)
327 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
332 int create_fifo_fds(struct logger *server, int fifo_id, int *write_fd, int *read_fd, bool dump)
338 if (snprintf(fifo_path, sizeof fifo_path, "/run/dlog/priv/fifo/%d", fifo_id) < 0)
341 if (mkfifo(fifo_path, 0600) < 0) {
342 assert(errno != EEXIST);
348 *read_fd = open(fifo_path, O_RDONLY | O_NONBLOCK);
350 check_if_fd_limit_reached(server, errno);
355 *write_fd = open(fifo_path, O_WRONLY | O_NONBLOCK);
357 check_if_fd_limit_reached(server, errno);
363 /* Speed up dumping dlogutils by increasing their pipe size,
364 * as otherwise this pipe's size becomes a major bottleneck.
366 * Continuous connections don't really care if the initial
367 * burst of "historic" logs is slow and the following flow
368 * of logs is just fine with a small pipe. Meanwhile they
369 * live for a long time during which they would take away
370 * from the valuable total pipe size. */
372 if (fcntl(*write_fd, F_SETPIPE_SZ, DUMPING_READER_PIPE_SIZE) < 0) {
373 /* Ignore; this is just a performance optimisation
374 * and doesn't affect functionality so while errors
375 * are worrisome they not a big deal or something
376 * we can do anything about, at any rate. */
384 static int create_logger_subreader_from_dlogutil_line(struct dlogutil_line_params *params)
386 if (params->file_path) {
387 int retval = logfile_set_path(¶ms->file, params->file_path);
391 retval = logfile_open(¶ms->file);
396 if (params->buf_id == LOG_ID_INVALID)
399 if (params->file.path == NULL)
402 struct reader_logger *const reader = g_backend.logger_readers[params->buf_id];
406 return reader_logger_add_subreader_file(reader, params->filter, ¶ms->file);
409 static int create_reader_pipe_from_dlogutil_line(struct dlogutil_line_params *params, struct logger *server, struct reader_pipe **rd)
414 __attribute__((cleanup(reader_pipe_cleanup))) struct reader_pipe *reader = NULL;
417 if (params->file_path) {
418 retval = logfile_set_path(¶ms->file, params->file_path);
422 retval = logfile_open(¶ms->file);
427 if (params->buf_id == LOG_ID_INVALID)
430 if (params->file.path == NULL)
433 retval = reader_pipe_init(&reader, params->buf_id, server, params->filter, ¶ms->file, params->monitor, params->is_dumping);
444 * @brief Service a socket request
445 * @details Handle a socket request
446 * @param[in] server The logger server
447 * @param[in] wr The writer who sent the request
448 * @param[in] event The event containing the request
449 * @return 0 on success, else -errno
451 int service_writer_socket(struct logger* server, struct writer* wr, struct epoll_event* event)
456 struct dlog_control_msg* const msg = (struct dlog_control_msg*) wr->buffer;
459 if (event->events & EPOLLIN)
460 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
462 if ((r == 0 || r == -1) && event->events & EPOLLHUP)
469 /* The socket is SOCK_STREAM (see `listen_fd_create`), so one message
470 * could be split into chunks returned across multiple read() calls. */
471 if (wr->readed < sizeof(msg->length)
472 || wr->readed < msg->length)
473 goto dont_process_yet_and_read_more_data;
475 assert(wr->service_socket);
476 r = wr->service_socket(server, wr, msg);
480 dont_process_yet_and_read_more_data:
481 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
482 } while (r > 0 || ((wr->readed >= sizeof(msg->length) && wr->readed >= msg->length)));
484 return (r >= 0 || errno == EAGAIN) ? 0 : r;
488 * @brief Service /dev/kmsg
489 * @details Read from the /dev/kmsg device
490 * @param[in] server The logger server
491 * @param[in] wr The writer who sent the request
492 * @param[in] event The relevant event
493 * @return 0 on success, else -errno
495 int service_writer_kmsg(struct logger* server, struct writer* wr, struct epoll_event* event)
498 if (event->events & EPOLLHUP)
500 if (!(event->events & EPOLLIN))
503 /* The KMSG device returns just 1 log per read() so it is done in a loop.
504 * In theory this could starve everything else out if logs appeared faster
505 * than the daemon could process them, which would then necessitate some
506 * sort of throttling. In practice, KMSG doesn't really get flooded with
507 * logs the same way Android Logger devices are so the throttling is mostly
508 * there because we get it for free anyway and consistency doesn't hurt. */
510 int max_loop_iterations = g_backend.logger_device_throttling[LOG_ID_KMSG];
511 while (max_loop_iterations--) {
512 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
514 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
516 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
523 wr->buffer[r] = '\0';
524 struct dlogutil_entry_with_msg lem;
525 if (parse_kmsg_message(wr->buffer, &lem, r)) {
526 // don't signal an error: KMSG writer is too important to remove; besides, it would not get fixed that way.
529 add_recv_timestamp(&lem.header, server->time);
530 r = buffer_append(&lem.header, wr->buf_ptr);
538 void remove_reader_fd_entities(struct logger *server, struct reader *reader)
542 if (reader->fd_entity_sink.fd >= 0)
543 remove_fd_entity(&server->epoll_common, &reader->fd_entity_sink);
544 if (reader->fd_entity_source.fd >= 0)
545 remove_fd_entity(&server->epoll_common, &reader->fd_entity_source);
548 static bool cond_service_reader_pipe(void *ptr, void *user_data)
552 struct reader_pipe *reader = (struct reader_pipe *)ptr;
553 struct logger *logger = (struct logger *)user_data;
555 if (!logger->exiting && reader_should_buffer(reader, &logger->buf_params, logger->time.mono))
558 int r = print_out_logs(reader, logger->time);
561 remove_reader_fd_entities(logger, &reader->common);
562 reader_pipe_free(reader);
566 /* `service_reader()` returns -1 if everything was flushed, or 0 if
567 * a mild error happened that can be recovered from simply by waiting,
568 * the prime example being the pipe getting clogged. As soon as the
569 * reader is available again, we'd like to know about it to ensure
570 * logs are flushed as quickly as possible, which is why the EPOLLOUT.
572 * On the other hand, we don't want to remove readers from epoll even
573 * if they successfully flushed and have no logs to wait for. Consider
574 * the case where a buffer is unused (for example through libdlog's
575 * buffer disabling feature). If we relied on receiving an error on
576 * calling `write()` to learn that the connection had been closed,
577 * we would never learn about it because there would be no incoming
578 * logs to trigger the flush and so any FDs representing connections
579 * to such buffer would leak until a log finally arrived (which could
580 * be never). This is why waiting is also done on EPOLLHUP. */
581 if (modify_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) {
582 /* ignore, can't really happen and it's not
583 * like we can do anything about it either */
589 static bool cond_service_reader_logger(void *ptr, void *user_data)
593 struct reader_logger *reader = (struct reader_logger *)ptr;
594 struct logger *logger = (struct logger *)user_data;
596 int r = service_reader_logger(reader, logger->time);
599 remove_reader_fd_entities(logger, &reader->common);
600 reader_logger_free(reader);
604 /* `service_reader()` returns -1 if everything was flushed, or 0 if
605 * a mild error happened that can be recovered from simply by waiting,
606 * the prime example being the pipe getting clogged. As soon as the
607 * reader is available again, we'd like to know about it to ensure
608 * logs are flushed as quickly as possible, which is why the EPOLLOUT.
610 * On the other hand, we don't want to remove readers from epoll even
611 * if they successfully flushed and have no logs to wait for. Consider
612 * the case where a buffer is unused (for example through libdlog's
613 * buffer disabling feature). If we relied on receiving an error on
614 * calling `write()` to learn that the connection had been closed,
615 * we would never learn about it because there would be no incoming
616 * logs to trigger the flush and so any FDs representing connections
617 * to such buffer would leak until a log finally arrived (which could
618 * be never). This is why waiting is also done on EPOLLHUP. */
619 if (modify_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) {
620 /* ignore, can't really happen and it's not
621 * like we can do anything about it either */
628 * @brief Service syslog
629 * @details Read from the syslog socket
630 * @param[in] server The logger server
631 * @param[in] wr The writer who sent the request
632 * @param[in] event The relevant event
633 * @return 0 on success, else -errno
635 int service_writer_syslog(struct logger* server, struct writer* wr, struct epoll_event* event)
637 if (event->events & EPOLLHUP)
639 if (!(event->events & EPOLLIN))
642 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
644 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
646 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
653 wr->buffer[r] = '\0';
655 struct dlogutil_entry_with_msg lem;
656 if (parse_syslog_datagram(wr->buffer, r + 1, &lem.header)) {
657 /* don't return parse error as writers are removed then */
661 add_recv_timestamp(&lem.header, server->time);
662 return buffer_append(&lem.header, wr->buf_ptr);
666 * @brief Service all readers
667 * @details Update all readers with latest data
668 * @param[in] server The logger server
669 * @param[in] force_push Whether to force logs to be pushed to the readers
671 static void service_all_readers(struct logger *server)
673 for (int i = 0; i < LOG_ID_MAX; i++) {
674 struct log_buffer *const buffer = server->buffers[i];
678 list_remove_if(&buffer->readers_pipe, server, cond_service_reader_pipe);
680 list_remove_if(&server->readers_logger, server, cond_service_reader_logger);
684 * @brief Add writer to server
685 * @details Adds a writer to the server's witers list and registers its event to epoll loop
686 * @param[in] l The server to add the writer to
687 * @param[in] writer The writer to add to the server and register its working_fd to epoll loop
689 void logger_add_writer(struct logger* l, struct writer* wr)
694 list_add(&l->writers, wr);
695 add_fd_entity(&l->epoll_common, &wr->fd_entity);
698 int epoll_metadata_initialize(struct epoll_metadata *metadata)
700 metadata->fd = epoll_create1(0);
701 if (metadata->fd < 0)
704 int r = initialize_epoll_size(&metadata->events, &metadata->events_size);
715 void epoll_metadata_destroy(struct epoll_metadata *metadata)
717 if (metadata->fd >= 0)
720 free(metadata->events);
724 * @brief Create the logger server
725 * @details Allocate the logger server's auxiliary structures (buffers etc.)
726 * @param[in] data Initialisation data
727 * @param[out] l The logger server
728 * @return 0 on success, -errno on failure
730 static int logger_create(struct logger_config_data *data, struct logger *l)
732 memset(l, 0, sizeof *l);
733 l->epoll_socket.fd = -1;
735 int r = epoll_metadata_initialize(&l->epoll_common);
738 r = epoll_metadata_initialize(&l->epoll_socket);
742 l->epolltime = data->epoll_time;
744 l->lazy_polling_total = data->lazy_polling_total;
745 l->lazy_polling_sleep = data->lazy_polling_sleep;
747 l->buf_params = data->buf_params;
749 l->qos.log_metrics = metrics_create();
750 if (!l->qos.log_metrics)
753 l->qos.max_throughput = data->qos_max_throughput;
754 l->qos.threshold = data->qos_threshold;
755 l->qos.threshold_reapply = data->qos_threshold_reapply;
756 l->qos.limit_duration = data->qos_limit_duration;
757 l->qos.file_path = data->qos_file_path;
758 data->qos_file_path = NULL;
760 // Check if the daemon is being launched for the first time since reboot
762 if (data->first_time_file_path) {
763 int fd = open(data->first_time_file_path, O_CREAT | O_EXCL | O_RDONLY, 0644);
774 // If no path, assume first time
777 if (g_backend.use_logger_by_default)
778 for (log_id_t id = 0; id < LOG_ID_MAX; ++id) {
779 if (!is_core_buffer(id))
782 int r = reader_logger_init(g_backend.logger_readers + id, id, l, !first_time);
785 if (!g_backend.logger_readers[id])
788 if (qos_is_enabled(&l->qos)) {
789 r = reader_logger_add_subreader_metrics(g_backend.logger_readers[id], &l->qos);
794 r = add_reader_logger(l, g_backend.logger_readers[id]);
799 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
800 if (data->is_buffer_enabled[id]) {
801 int r = buffer_create(&l->buffers[id], id, data->buffers + id);
806 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
807 if (l->buffers[id]) {
808 add_fd_entity(&l->epoll_common, &l->buffers[id]->sock_ctl.fd_entity);
809 add_fd_entity(&l->epoll_common, &l->buffers[id]->sock_wr.fd_entity);
811 add_fd_entity(&l->epoll_socket, &l->buffers[id]->sock_ctl.fd_entity);
812 add_fd_entity(&l->epoll_socket, &l->buffers[id]->sock_wr.fd_entity);
815 /* TODO: make writers creation optional/configurable */
816 int (*writers_factories[LOG_ID_MAX])(struct writer **writer, struct log_buffer *log_buf) = {
817 [LOG_ID_KMSG] = create_kmsg_writer,
818 [LOG_ID_SYSLOG] = create_syslog_writer,
820 for (unsigned u = 0; u < NELEMS(writers_factories); ++u)
821 if (writers_factories[u] && data->is_buffer_enabled[u]) {
823 int r = writers_factories[u](&wr, l->buffers[u]);
827 logger_add_writer(l, wr);
833 static bool cond_writer_free(void *ptr, void *user_data)
835 writer_free((struct writer *)ptr, (struct logger *)user_data);
841 * @details Deallocate the logger and its auxiliary structures
842 * @param[in] l The logger server
844 static void logger_free(struct logger *l)
848 list_remove_if(&l->writers, l, cond_writer_free);
849 list_remove_if(&l->readers_logger, l, cond_reader_logger_free);
852 for (j = 0; j < LOG_ID_MAX; j++)
854 buffer_free(l->buffers[j], l);
856 epoll_metadata_destroy(&l->epoll_common);
857 epoll_metadata_destroy(&l->epoll_socket);
863 * @brief Handle interrupting/terminating signals
864 * @details Clears global flag to stop main loop
865 * @param[in] signo signal number
867 static void handle_signals(int signo)
873 static void ensure_epoll_size(struct epoll_event **events, unsigned *size, unsigned wanted_size)
878 if (wanted_size <= *size)
881 typeof(*events) temp = realloc(*events, wanted_size * sizeof **events);
889 static int initialize_epoll_size(struct epoll_event **events, unsigned *size)
894 static const size_t default_size = 16U;
895 typeof(*events) ev = malloc(default_size * sizeof *ev);
900 *size = default_size;
904 void dispatch_epoll_event(struct logger *server, struct epoll_event *event)
906 struct fd_entity *const entity = (struct fd_entity *) event->data.ptr;
907 assert(entity->dispatch_event);
908 entity->dispatch_event(server, event, entity->dispatch_data);
911 int handle_epoll_events(struct logger *server, struct epoll_metadata *metadata, int timeout)
913 ensure_epoll_size(&metadata->events, &metadata->events_size, metadata->cnt);
915 int nfds = epoll_wait(metadata->fd, metadata->events, metadata->events_size, timeout);
917 return errno == EINTR ? 0 : -errno;
919 for (int i = 0; i < nfds; i++)
920 dispatch_epoll_event(server, metadata->events + i);
925 int sleep_while_handling_socket(struct logger *server, struct epoll_metadata *metadata, int timeout)
928 int r = handle_epoll_events(server, metadata, timeout);
933 clock_gettime(CLOCK_MONOTONIC, &now);
934 timeout -= (now.tv_sec - server->time.mono.tv_sec ) * S_TO_MS
935 + (now.tv_nsec - server->time.mono.tv_nsec) / MS_TO_NS;
936 server->time.mono.tv_sec = now.tv_sec;
937 server->time.mono.tv_nsec = now.tv_nsec;
939 clock_gettime(CLOCK_REALTIME, &server->time.real);
940 } while (timeout > 0);
947 * @details The main logging loop
948 * @param[in] server The logger server
949 * @return 0 on success, else -errno
951 static int do_logger(struct logger* server)
953 struct sigaction action = {
954 .sa_handler = handle_signals,
957 sigemptyset(&action.sa_mask);
959 static const int handled_signals[] = { SIGINT, SIGTERM };
960 for (unsigned u = 0; u < NELEMS(handled_signals); ++u)
961 sigaction(handled_signals[u], &action, NULL);
963 bool use_lazy_polling = true;
964 while (g_logger_run) {
965 clock_gettime(CLOCK_MONOTONIC, &server->time.mono);
966 clock_gettime(CLOCK_REALTIME, &server->time.real);
968 if (server->lazy_polling_total >= 0) {
969 server->lazy_polling_total -= server->lazy_polling_sleep;
970 use_lazy_polling = (server->lazy_polling_total >= 0);
972 if (use_lazy_polling)
973 sleep_while_handling_socket(server, &server->epoll_socket, server->lazy_polling_sleep);
975 int r = handle_epoll_events(server, &server->epoll_common, server->epolltime * !use_lazy_polling);
979 service_all_readers(server);
980 qos_periodic_check(server);
983 /* ensure all logs are written no matter when the program was interrupted */
985 service_all_readers(server);
991 * @brief Prepare socket data
992 * @details Extracts initialisation data specific to each socket
993 * @param[in] conf Config database
994 * @param[out] data Socket init config data
995 * @param[in] buf_name The name of the buffer the socket belongs to
996 * @param[in] type The name of the buffer type
997 * @return 0 on success, -errno on failure
999 int prepare_socket_data(const struct log_config *conf, struct socket_config_data *data, char *buf_name, const char *type)
1001 char conf_key[MAX_CONF_KEY_LEN];
1004 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock", buf_name, type);
1007 const char * const path = log_config_get(conf, conf_key);
1009 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock_rights", buf_name, type);
1012 const char * const permissions_str = log_config_get(conf, conf_key);
1014 if (!permissions_str || !path)
1017 data->permissions = parse_permissions(permissions_str);
1018 if (data->permissions <= 0)
1021 strncpy(data->path, path, MAX_CONF_VAL_LEN - 1);
1027 * @brief Prepare buffer data
1028 * @details Extracts data specific for each buffer
1029 * @param[in] conf Config database
1030 * @param[out] data Buffer init config data
1031 * @param[in] buf_id Index of the buffer to work with
1032 * @return 0 on success, -errno on failure
1034 int prepare_buffer_data(const struct log_config *conf, struct buffer_config_data *data, log_id_t buf_id)
1036 char * const buf_name = log_name_by_id(buf_id);
1037 char * validity_check_ptr;
1038 char conf_key[MAX_CONF_KEY_LEN];
1041 r = prepare_socket_data(conf, &data->write_socket, buf_name, "write");
1045 r = prepare_socket_data(conf, &data->ctl_socket, buf_name, "ctl");
1049 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_size", buf_name);
1053 const char * const size_str = log_config_get(conf, conf_key);
1057 data->size = strtol(size_str, &validity_check_ptr, 10);
1058 if (*validity_check_ptr)
1060 if (data->size <= 0)
1067 * @brief Save logfile line
1068 * @detail Saves logfile config line in user_data list
1069 * @param[in] key Config entry key
1070 * @param[in] value Config entry value
1071 * @param[in] userdata Userdata
1073 void save_logfile_config(char const *key, char const *value, void *userdata)
1076 if (strncmp(key, CONF_PREFIX, sizeof CONF_PREFIX - 1))
1079 struct logger_config_data *data = (struct logger_config_data *)userdata;
1080 void *cmd = (void *)strdup(value);
1082 list_add(&data->logfile_configs, cmd);
1087 * @brief Initialize config data
1088 * @param[out] The data structure to fill with initial values
1090 void initialize_config_data(struct logger_config_data *data)
1092 memset(data, 0, sizeof *data);
1096 * @brief Prepare config data
1097 * @details Extracts relevant config data for logger initialisation
1098 * @param[out] data Parsed configuration
1099 * @return 0 on success, -errno on failure
1101 int prepare_config_data(struct logger_config_data *data)
1105 struct log_config conf;
1106 int ret = log_config_read(&conf);
1110 const dlogutil_sorting_order_e sort_by = get_order_from_config(&conf);
1112 int throttling_default = log_config_get_int(&conf, "logger_dev_throttling", LOGGER_DEVICE_THROTTLING_DEFAULT);
1113 const char *const dynamic_config_dir = log_config_get(&conf, DYNAMIC_CONFIG_CONF_KEY);
1115 const char * const backend = log_config_get(&conf, "backend");
1121 for (int i = 0; i < LOG_ID_MAX; i++) {
1122 char key[MAX_CONF_KEY_LEN];
1123 const int r = snprintf(key, sizeof key, "logger_dev_throttling_%s", log_name_by_id((log_id_t)i));
1127 g_backend.logger_device_throttling[i] = max_int(1, log_config_get_int(&conf, key, throttling_default));
1130 if (dynamic_config_dir && dynamic_config_dir[0] == '/') {
1131 data->dynamic_config_dir = strdup(dynamic_config_dir);
1132 if (!data->dynamic_config_dir) {
1137 data->dynamic_config_dir = NULL; // Technically unnecessary but no reason not to put it
1140 data->epoll_time = log_config_get_int(&conf, "epoll_time_ms", DEFAULT_EPOLL_TIME_MS);
1141 data->lazy_polling_total = log_config_get_int(&conf, "lazy_polling_total_ms", DEFAULT_LAZY_POLLING_TOTAL_MS);
1142 data->lazy_polling_sleep = log_config_get_int(&conf, "lazy_polling_sleep_ms", DEFAULT_LAZY_POLLING_SLEEP_MS);
1144 const char *const qos_file_path = log_config_get(&conf, "qos_file_path");
1145 data->qos_file_path = qos_file_path ? strdup(qos_file_path) : NULL;
1147 data->qos_limit_duration = log_config_get_int(&conf, "qos_refresh_rate_s", DEFAULT_QOS_LIMIT_DURATION_S);
1148 data->qos_max_throughput = log_config_get_int(&conf, "qos_max_throughput_logs", DEFAULT_QOS_THROUGHPUT_LOGS);
1149 data->qos_threshold = log_config_get_int(&conf, "qos_threshold_logs", DEFAULT_QOS_THRESHOLD_LOGS);
1150 data->qos_threshold_reapply = log_config_get_int(&conf, "qos_threshold_reapply_logs", DEFAULT_QOS_THRESHOLD_REAPPLY_LOGS);
1153 void (*func)(struct qos_module *qos, struct metrics_pid_aggr_info *infos, int count);
1155 } const qos_methods[] = {
1156 { qos_distribution_proportional_raw , "proportional_raw" },
1157 { qos_distribution_proportional_talmud, "proportional_talmud" },
1158 { qos_distribution_equal , "equal" },
1159 { qos_distribution_equal_dual , "equal_dual" },
1160 { qos_distribution_equal_multi , "equal_multi" },
1162 qos_distribution_func = qos_distribution_equal_multi; // default
1163 const char *const qos_method = log_config_get(&conf, "qos_method");
1165 for (int i = 0; i < NELEMS(qos_methods); ++i)
1166 if (!strcmp(qos_method, qos_methods[i].name))
1167 qos_distribution_func = qos_methods[i].func;
1169 const char *const first_time_file_path = log_config_get(&conf, "first_time_file_path");
1170 data->first_time_file_path = first_time_file_path ? strdup(first_time_file_path) : NULL;
1172 memset(data->is_buffer_enabled, 0, sizeof(data->is_buffer_enabled));
1173 if (!strcmp(backend, "pipe")) {
1174 data->is_buffer_enabled[LOG_ID_MAIN] =
1175 data->is_buffer_enabled[LOG_ID_RADIO] =
1176 data->is_buffer_enabled[LOG_ID_SYSTEM] =
1177 data->is_buffer_enabled[LOG_ID_APPS] = 1;
1178 g_backend.use_logger_by_default = false;
1179 } else if (!strcmp(backend, "logger")) {
1180 g_backend.use_logger_by_default = true;
1181 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
1182 const char *const logger_device = log_config_get(&conf, log_name_by_id(buf_id));
1184 strncpy(g_backend.logger_devices[buf_id], logger_device,
1185 NELEMS(g_backend.logger_devices[buf_id]) - 1);
1191 data->is_buffer_enabled[LOG_ID_KMSG] = log_config_get_boolean(&conf, "handle_kmsg", true);
1192 data->is_buffer_enabled[LOG_ID_SYSLOG] =
1193 dev_log_sock_get() >= 0 || log_config_get_boolean(&conf, "syslog_force", false);
1195 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
1196 if (data->is_buffer_enabled[buf_id]) {
1197 ret = prepare_buffer_data(&conf, data->buffers + buf_id, buf_id);
1200 data->buffers[buf_id].sort_by = sort_by;
1203 data->logfile_configs = NULL;
1204 log_config_foreach(&conf, save_logfile_config, data);
1207 log_config_free(&conf);
1211 static bool cond_string_free(void *ptr, void *user_data)
1218 static void free_config_data(struct logger_config_data *data)
1220 list_remove_if(&data->logfile_configs, NULL, cond_string_free);
1221 free(data->dynamic_config_dir);
1222 free(data->qos_file_path);
1223 free(data->first_time_file_path);
1227 * @brief Parse logfile line
1228 * @detail Parses a logfile config line
1229 * @param[in] key Config entry key
1230 * @param[in] value Config entry value
1231 * @param[in] userdata Userdata
1233 void parse_logfile_config(void *value, void *userdata)
1238 struct logger *server = (struct logger *) userdata;
1239 char *configline = (char *) value;
1241 __attribute__((cleanup(free_dlogutil_line_params))) struct dlogutil_line_params params;
1242 if (!initialize_dlogutil_line_params(¶ms))
1245 get_dlogutil_line_params(configline, ¶ms);
1248 if (g_backend.use_logger_by_default && is_core_buffer(params.buf_id)) {
1249 r = create_logger_subreader_from_dlogutil_line(¶ms);
1251 struct reader_pipe *reader = NULL;
1252 r = create_reader_pipe_from_dlogutil_line(¶ms, server, &reader);
1254 add_reader_pipe(server, reader);
1259 printf("Warning: unable to add logutil reader for provided configuration. Ignoring.\n"
1260 " Config line: %s\n"
1261 " Reason given: %m\n",
1269 * @details Prints basic usage tips
1273 printf("Usage: %s [options]\n"
1274 "\t-h Show this help\n"
1275 "\t-b N Set the size of the log buffer (in bytes)\n"
1276 "\t-t N Set time between writes to file (in seconds)\n",
1277 program_invocation_short_name);
1282 * @details Parses execution parameters of the program
1283 * @param[in] argc Argument count
1284 * @param[in] argv Argument values
1285 * @param[out] b Buffering parameters
1286 * @return 0 or 1 on success, else -errno. Nonzero if the program is to close.
1288 static int parse_args(int argc, char **argv, struct buf_params *b)
1290 b->time = BUF_PARAM_TIME_DEFAULT;
1291 b->bytes = BUF_PARAM_BYTES_DEFAULT;
1293 __attribute__((cleanup(reset_getopt_internals))) int option;
1294 while ((option = getopt(argc, argv, "hb:t:")) != -1) {
1297 if (!isdigit(optarg[0]))
1299 b->time = clamp_int(atoi(optarg), BUF_PARAM_TIME_MIN, BUF_PARAM_TIME_MAX);
1302 if (!isdigit(optarg[0]))
1304 b->bytes = clamp_int(atoi(optarg), BUF_PARAM_BYTES_MIN, BUF_PARAM_BYTES_MAX);
1317 * @brief Finalize initialisation
1318 * @details Do misc stuff needed at the end of the initialisation
1319 * @param[in] data configuration dat to read logfiles config lines from
1320 * @param[in] server logger instance to configure
1321 * @return 0 on success, -errno on failure
1323 static int finalize_init(struct logger_config_data *data, struct logger *server)
1325 int r = sd_notify(0, "READY=1");
1329 // used to populate the first readers
1330 clock_gettime(CLOCK_MONOTONIC, &server->time.mono);
1331 clock_gettime(CLOCK_REALTIME, &server->time.real);
1333 //create files after resetting self privileges
1334 list_foreach(data->logfile_configs, server, parse_logfile_config);
1339 static void precreate_logctl_file(struct logger_config_data *data)
1341 char *logctl_file_path = NULL;
1342 if (asprintf(&logctl_file_path, "%s/%s", data->dynamic_config_dir, DYNAMIC_CONFIG_FILENAME) < 0)
1343 // This is worrying but unimportant
1346 int fd = open(logctl_file_path, O_RDONLY | O_CREAT, 0644);
1348 // Again, no big deal
1356 * @return 0 on success, nonzero on failure
1357 * @retval 1 Configuration error
1358 * @retval 2 Runtime error
1360 int main(int argc, char** argv)
1364 signal(SIGPIPE, SIG_IGN);
1366 r = reset_self_privileges();
1369 printf("Unable to drop privileges to build-time defaults (%m). Exiting.\n");
1370 return DLOG_EXIT_ERR_RUNTIME;
1373 struct logger_config_data data;
1374 initialize_config_data(&data);
1376 if ((r = parse_args(argc, argv, &data.buf_params)) != 0) {
1380 return DLOG_EXIT_SUCCESS; // --help option
1383 printf("Unable to parse command line args (%m). Exiting.\n");
1384 return DLOG_EXIT_ERR_CONFIG;
1387 if ((r = prepare_config_data(&data)) != 0) {
1389 printf("Unable to prepare config (%m). Exiting.\n");
1390 return DLOG_EXIT_ERR_CONFIG;
1393 precreate_logctl_file(&data);
1395 struct logger server;
1396 if ((r = logger_create(&data, &server)) < 0) {
1398 printf("Unable to initialize logger with provided configuration (%m). Exiting.\n");
1399 ret = DLOG_EXIT_ERR_CONFIG;
1403 if ((r = finalize_init(&data, &server)) < 0) {
1405 printf("Unable to finalize initialisation (%m). Exiting.\n");
1406 ret = DLOG_EXIT_ERR_CONFIG;
1410 if ((r = do_logger(&server)) < 0) {
1412 printf("Runtime failure (%m). Exiting.\n");
1413 ret = DLOG_EXIT_ERR_RUNTIME;
1417 ret = DLOG_EXIT_SUCCESS;
1420 free_config_data(&data);
1421 logger_free(&server);