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 flush_logfile_timely(struct log_file *file, struct timespec ts, int flush_time)
229 if (file->buffer.position > 0) {
230 if (ts.tv_sec - file->buffer.oldest_log.tv_sec +
231 (ts.tv_nsec > file->buffer.oldest_log.tv_nsec ? 1 : 0) >
237 void reader_notify_losing_log(const dlogutil_entry_s *le, void *reader_)
239 struct reader_pipe *reader = (struct reader_pipe *) reader_;
242 reader_print_out_single_log(reader, (dlogutil_entry_s *)le);
246 * @brief Add reader to log buffer
247 * @details Adds a reader to the log buffers reader list
248 * @param[in] log_buffer The buffer whither to add the reader
249 * @param[in] reader The reader to add to the buffer
250 * @return 0 on success, -ENOMEM on memory allocation error
252 int add_buffer_reader(struct log_buffer *buffer, struct reader_pipe *reader)
257 reader->log_storage_reader_ptr = log_storage_new_reader(buffer->log_storage_ptr,
258 reader->is_dumping, reader->monitor, reader_notify_losing_log, reader);
260 if (!reader->log_storage_reader_ptr)
263 return list_add(&buffer->readers_pipe, reader) ? 0 : -ENOMEM;
266 int add_reader_pipe(struct logger *server, struct reader_pipe *reader)
271 if (reader->common.fd_entity_sink.fd >= 0) {
272 /* Readers who write to file have no sink FD entity (or, strictly
273 * speaking, they do have one but it is not filled) since a file
274 * is not eligible to be added to epoll. However, the entity primarily
275 * serves to handle pipes getting clogged mid-write (which cannot
276 * happen for files) and is not involved in starting a write,
277 * which is handled by the source FD entity, not sink (and which is
278 * also done periodically for all readers anyway regardless
279 * of whether they've been added to epoll or not). The other use
280 * case for epoll - the one where connection FDs leak for unused
281 * buffers - is not a problem here because the daemon is not
282 * supposed to ever stop writing to files. */
284 int r = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
290 ret = add_buffer_reader(reader->buf_ptr, reader);
291 if (ret < 0 && reader->common.fd_entity_sink.fd >= 0)
292 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
297 static int add_reader_logger(struct logger *server, struct reader_logger *reader)
302 if (reader->common.fd_entity_sink.fd >= 0) {
303 /* Readers who write to file have no sink FD entity (or, strictly
304 * speaking, they do have one but it is not filled) since a file
305 * is not eligible to be added to epoll. However, the entity primarily
306 * serves to handle pipes getting clogged mid-write (which cannot
307 * happen for files) and is not involved in starting a write,
308 * which is handled by the source FD entity, not sink (and which is
309 * also done periodically for all readers anyway regardless
310 * of whether they've been added to epoll or not). The other use
311 * case for epoll - the one where connection FDs leak for unused
312 * buffers - is not a problem here because the daemon is not
313 * supposed to ever stop writing to files. */
315 int r = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
322 assert(reader->common.fd_entity_source.fd >= 0);
323 ret = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_source);
327 if (!list_add(&server->readers_logger, reader)) {
328 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_source);
336 if (reader->common.fd_entity_sink.fd >= 0)
337 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
342 int create_fifo_fds(struct logger *server, int fifo_id, int *write_fd, int *read_fd, bool dump)
348 if (snprintf(fifo_path, sizeof fifo_path, "/run/dlog/priv/fifo/%d", fifo_id) < 0)
351 if (mkfifo(fifo_path, 0600) < 0) {
352 assert(errno != EEXIST);
358 *read_fd = open(fifo_path, O_RDONLY | O_NONBLOCK);
360 check_if_fd_limit_reached(server, errno);
365 *write_fd = open(fifo_path, O_WRONLY | O_NONBLOCK);
367 check_if_fd_limit_reached(server, errno);
373 /* Speed up dumping dlogutils by increasing their pipe size,
374 * as otherwise this pipe's size becomes a major bottleneck.
376 * Continuous connections don't really care if the initial
377 * burst of "historic" logs is slow and the following flow
378 * of logs is just fine with a small pipe. Meanwhile they
379 * live for a long time during which they would take away
380 * from the valuable total pipe size. */
382 if (fcntl(*write_fd, F_SETPIPE_SZ, DUMPING_READER_PIPE_SIZE) < 0) {
383 /* Ignore; this is just a performance optimisation
384 * and doesn't affect functionality so while errors
385 * are worrisome they not a big deal or something
386 * we can do anything about, at any rate. */
394 static int create_logger_subreader_from_dlogutil_line(struct dlogutil_line_params *params)
396 if (params->file_path) {
397 int retval = logfile_set_path(¶ms->file, params->file_path);
401 retval = logfile_open(¶ms->file);
406 if (params->buf_id == LOG_ID_INVALID)
409 if (params->file.path == NULL)
412 struct reader_logger *const reader = g_backend.logger_readers[params->buf_id];
416 return reader_logger_add_subreader_file(reader, params->filter, ¶ms->file);
419 static int create_reader_pipe_from_dlogutil_line(struct dlogutil_line_params *params, struct logger *server, struct reader_pipe **rd)
424 __attribute__((cleanup(reader_pipe_cleanup))) struct reader_pipe *reader = NULL;
427 if (params->file_path) {
428 retval = logfile_set_path(¶ms->file, params->file_path);
432 retval = logfile_open(¶ms->file);
437 if (params->buf_id == LOG_ID_INVALID)
440 if (params->file.path == NULL)
443 retval = reader_pipe_init(&reader, params->buf_id, server, params->filter, ¶ms->file, params->monitor, params->is_dumping);
454 * @brief Service a socket request
455 * @details Handle a socket request
456 * @param[in] server The logger server
457 * @param[in] wr The writer who sent the request
458 * @param[in] event The event containing the request
459 * @return 0 on success, else -errno
461 int service_writer_socket(struct logger* server, struct writer* wr, struct epoll_event* event)
466 struct dlog_control_msg* const msg = (struct dlog_control_msg*) wr->buffer;
469 if (event->events & EPOLLIN)
470 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
472 if ((r == 0 || r == -1) && event->events & EPOLLHUP)
479 /* The socket is SOCK_STREAM (see `listen_fd_create`), so one message
480 * could be split into chunks returned across multiple read() calls. */
481 if (wr->readed < sizeof(msg->length)
482 || wr->readed < msg->length)
483 goto dont_process_yet_and_read_more_data;
485 assert(wr->service_socket);
486 r = wr->service_socket(server, wr, msg);
490 dont_process_yet_and_read_more_data:
491 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
492 } while (r > 0 || ((wr->readed >= sizeof(msg->length) && wr->readed >= msg->length)));
494 return (r >= 0 || errno == EAGAIN) ? 0 : r;
498 * @brief Service /dev/kmsg
499 * @details Read from the /dev/kmsg device
500 * @param[in] server The logger server
501 * @param[in] wr The writer who sent the request
502 * @param[in] event The relevant event
503 * @return 0 on success, else -errno
505 int service_writer_kmsg(struct logger* server, struct writer* wr, struct epoll_event* event)
508 if (event->events & EPOLLHUP)
510 if (!(event->events & EPOLLIN))
513 /* The KMSG device returns just 1 log per read() so it is done in a loop.
514 * In theory this could starve everything else out if logs appeared faster
515 * than the daemon could process them, which would then necessitate some
516 * sort of throttling. In practice, KMSG doesn't really get flooded with
517 * logs the same way Android Logger devices are so the throttling is mostly
518 * there because we get it for free anyway and consistency doesn't hurt. */
520 int max_loop_iterations = g_backend.logger_device_throttling[LOG_ID_KMSG];
521 while (max_loop_iterations--) {
522 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
524 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
526 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
533 wr->buffer[r] = '\0';
534 struct dlogutil_entry_with_msg lem;
535 if (parse_kmsg_message(wr->buffer, &lem, r)) {
536 // don't signal an error: KMSG writer is too important to remove; besides, it would not get fixed that way.
539 add_recv_timestamp(&lem.header, server->time);
540 r = buffer_append(&lem.header, wr->buf_ptr);
548 void remove_reader_fd_entities(struct logger *server, struct reader *reader)
552 if (reader->fd_entity_sink.fd >= 0)
553 remove_fd_entity(&server->epoll_common, &reader->fd_entity_sink);
554 if (reader->fd_entity_source.fd >= 0)
555 remove_fd_entity(&server->epoll_common, &reader->fd_entity_source);
558 static bool cond_service_reader_pipe(void *ptr, void *user_data)
562 struct reader_pipe *reader = (struct reader_pipe *)ptr;
563 struct logger *logger = (struct logger *)user_data;
565 int r = print_out_logs(reader, logger->time);
568 remove_reader_fd_entities(logger, &reader->common);
569 reader_pipe_free(reader);
573 /* `service_reader()` returns -1 if everything was flushed, or 0 if
574 * a mild error happened that can be recovered from simply by waiting,
575 * the prime example being the pipe getting clogged. As soon as the
576 * reader is available again, we'd like to know about it to ensure
577 * logs are flushed as quickly as possible, which is why the EPOLLOUT.
579 * On the other hand, we don't want to remove readers from epoll even
580 * if they successfully flushed and have no logs to wait for. Consider
581 * the case where a buffer is unused (for example through libdlog's
582 * buffer disabling feature). If we relied on receiving an error on
583 * calling `write()` to learn that the connection had been closed,
584 * we would never learn about it because there would be no incoming
585 * logs to trigger the flush and so any FDs representing connections
586 * to such buffer would leak until a log finally arrived (which could
587 * be never). This is why waiting is also done on EPOLLHUP. */
588 if (modify_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) {
589 /* ignore, can't really happen and it's not
590 * like we can do anything about it either */
593 flush_logfile_timely(&reader->file, logger->time.mono, logger->buf_params.time);
598 static bool cond_service_reader_logger(void *ptr, void *user_data)
602 struct reader_logger *reader = (struct reader_logger *)ptr;
603 struct logger *logger = (struct logger *)user_data;
605 int r = service_reader_logger(reader, logger->time);
608 remove_reader_fd_entities(logger, &reader->common);
609 reader_logger_free(reader);
613 /* `service_reader()` returns -1 if everything was flushed, or 0 if
614 * a mild error happened that can be recovered from simply by waiting,
615 * the prime example being the pipe getting clogged. As soon as the
616 * reader is available again, we'd like to know about it to ensure
617 * logs are flushed as quickly as possible, which is why the EPOLLOUT.
619 * On the other hand, we don't want to remove readers from epoll even
620 * if they successfully flushed and have no logs to wait for. Consider
621 * the case where a buffer is unused (for example through libdlog's
622 * buffer disabling feature). If we relied on receiving an error on
623 * calling `write()` to learn that the connection had been closed,
624 * we would never learn about it because there would be no incoming
625 * logs to trigger the flush and so any FDs representing connections
626 * to such buffer would leak until a log finally arrived (which could
627 * be never). This is why waiting is also done on EPOLLHUP. */
628 if (modify_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) {
629 /* ignore, can't really happen and it's not
630 * like we can do anything about it either */
633 reader_logger_flush(reader, logger->time.mono, logger->buf_params.time);
638 * @brief Service syslog
639 * @details Read from the syslog socket
640 * @param[in] server The logger server
641 * @param[in] wr The writer who sent the request
642 * @param[in] event The relevant event
643 * @return 0 on success, else -errno
645 int service_writer_syslog(struct logger* server, struct writer* wr, struct epoll_event* event)
647 if (event->events & EPOLLHUP)
649 if (!(event->events & EPOLLIN))
652 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
654 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
656 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
663 wr->buffer[r] = '\0';
665 struct dlogutil_entry_with_msg lem;
666 if (parse_syslog_datagram(wr->buffer, r + 1, &lem.header)) {
667 /* don't return parse error as writers are removed then */
671 add_recv_timestamp(&lem.header, server->time);
672 return buffer_append(&lem.header, wr->buf_ptr);
676 * @brief Service all readers
677 * @details Update all readers with latest data
678 * @param[in] server The logger server
679 * @param[in] force_push Whether to force logs to be pushed to the readers
681 static void service_all_readers(struct logger *server)
683 for (int i = 0; i < LOG_ID_MAX; i++) {
684 struct log_buffer *const buffer = server->buffers[i];
688 list_remove_if(&buffer->readers_pipe, server, cond_service_reader_pipe);
690 list_remove_if(&server->readers_logger, server, cond_service_reader_logger);
694 * @brief Add writer to server
695 * @details Adds a writer to the server's witers list and registers its event to epoll loop
696 * @param[in] l The server to add the writer to
697 * @param[in] writer The writer to add to the server and register its working_fd to epoll loop
699 void logger_add_writer(struct logger* l, struct writer* wr)
704 list_add(&l->writers, wr);
705 add_fd_entity(&l->epoll_common, &wr->fd_entity);
708 int epoll_metadata_initialize(struct epoll_metadata *metadata)
710 metadata->fd = epoll_create1(0);
711 if (metadata->fd < 0)
714 int r = initialize_epoll_size(&metadata->events, &metadata->events_size);
725 void epoll_metadata_destroy(struct epoll_metadata *metadata)
727 if (metadata->fd >= 0)
730 free(metadata->events);
734 * @brief Create the logger server
735 * @details Allocate the logger server's auxiliary structures (buffers etc.)
736 * @param[in] data Initialisation data
737 * @param[out] l The logger server
738 * @return 0 on success, -errno on failure
740 static int logger_create(struct logger_config_data *data, struct logger *l)
742 memset(l, 0, sizeof *l);
743 l->epoll_socket.fd = -1;
745 int r = epoll_metadata_initialize(&l->epoll_common);
748 r = epoll_metadata_initialize(&l->epoll_socket);
752 l->epolltime = data->epoll_time;
754 l->lazy_polling_total = data->lazy_polling_total;
755 l->lazy_polling_sleep = data->lazy_polling_sleep;
757 l->buf_params = data->buf_params;
759 l->qos.log_metrics = metrics_create();
760 if (!l->qos.log_metrics)
763 l->qos.max_throughput = data->qos_max_throughput;
764 l->qos.threshold = data->qos_threshold;
765 l->qos.threshold_reapply = data->qos_threshold_reapply;
766 l->qos.limit_duration = data->qos_limit_duration;
767 l->qos.file_path = data->qos_file_path;
768 data->qos_file_path = NULL;
770 // Check if the daemon is being launched for the first time since reboot
772 if (data->first_time_file_path) {
773 int fd = open(data->first_time_file_path, O_CREAT | O_EXCL | O_RDONLY, 0644);
784 // If no path, assume first time
787 if (g_backend.use_logger_by_default)
788 for (log_id_t id = 0; id < LOG_ID_MAX; ++id) {
789 if (!is_core_buffer(id))
792 int r = reader_logger_init(g_backend.logger_readers + id, id, l, !first_time);
795 if (!g_backend.logger_readers[id])
798 if (qos_is_enabled(&l->qos)) {
799 r = reader_logger_add_subreader_metrics(g_backend.logger_readers[id], &l->qos);
804 r = add_reader_logger(l, g_backend.logger_readers[id]);
809 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
810 if (data->is_buffer_enabled[id]) {
811 int r = buffer_create(&l->buffers[id], id, data->buffers + id);
816 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
817 if (l->buffers[id]) {
818 add_fd_entity(&l->epoll_common, &l->buffers[id]->sock_ctl.fd_entity);
819 add_fd_entity(&l->epoll_common, &l->buffers[id]->sock_wr.fd_entity);
821 add_fd_entity(&l->epoll_socket, &l->buffers[id]->sock_ctl.fd_entity);
822 add_fd_entity(&l->epoll_socket, &l->buffers[id]->sock_wr.fd_entity);
825 /* TODO: make writers creation optional/configurable */
826 int (*writers_factories[LOG_ID_MAX])(struct writer **writer, struct log_buffer *log_buf) = {
827 [LOG_ID_KMSG] = create_kmsg_writer,
828 [LOG_ID_SYSLOG] = create_syslog_writer,
830 for (unsigned u = 0; u < NELEMS(writers_factories); ++u)
831 if (writers_factories[u] && data->is_buffer_enabled[u]) {
833 int r = writers_factories[u](&wr, l->buffers[u]);
837 logger_add_writer(l, wr);
843 static bool cond_writer_free(void *ptr, void *user_data)
845 writer_free((struct writer *)ptr, (struct logger *)user_data);
851 * @details Deallocate the logger and its auxiliary structures
852 * @param[in] l The logger server
854 static void logger_free(struct logger *l)
858 list_remove_if(&l->writers, l, cond_writer_free);
859 list_remove_if(&l->readers_logger, l, cond_reader_logger_free);
862 for (j = 0; j < LOG_ID_MAX; j++)
864 buffer_free(l->buffers[j], l);
866 epoll_metadata_destroy(&l->epoll_common);
867 epoll_metadata_destroy(&l->epoll_socket);
873 * @brief Handle interrupting/terminating signals
874 * @details Clears global flag to stop main loop
875 * @param[in] signo signal number
877 static void handle_signals(int signo)
883 static void ensure_epoll_size(struct epoll_event **events, unsigned *size, unsigned wanted_size)
888 if (wanted_size <= *size)
891 typeof(*events) temp = realloc(*events, wanted_size * sizeof **events);
899 static int initialize_epoll_size(struct epoll_event **events, unsigned *size)
904 static const size_t default_size = 16U;
905 typeof(*events) ev = malloc(default_size * sizeof *ev);
910 *size = default_size;
914 void dispatch_epoll_event(struct logger *server, struct epoll_event *event)
916 struct fd_entity *const entity = (struct fd_entity *) event->data.ptr;
917 assert(entity->dispatch_event);
918 entity->dispatch_event(server, event, entity->dispatch_data);
921 int handle_epoll_events(struct logger *server, struct epoll_metadata *metadata, int timeout)
923 ensure_epoll_size(&metadata->events, &metadata->events_size, metadata->cnt);
925 int nfds = epoll_wait(metadata->fd, metadata->events, metadata->events_size, timeout);
927 return errno == EINTR ? 0 : -errno;
929 for (int i = 0; i < nfds; i++)
930 dispatch_epoll_event(server, metadata->events + i);
935 int sleep_while_handling_socket(struct logger *server, struct epoll_metadata *metadata, int timeout)
938 int r = handle_epoll_events(server, metadata, timeout);
943 clock_gettime(CLOCK_MONOTONIC, &now);
944 timeout -= (now.tv_sec - server->time.mono.tv_sec ) * S_TO_MS
945 + (now.tv_nsec - server->time.mono.tv_nsec) / MS_TO_NS;
946 server->time.mono.tv_sec = now.tv_sec;
947 server->time.mono.tv_nsec = now.tv_nsec;
949 clock_gettime(CLOCK_REALTIME, &server->time.real);
950 } while (timeout > 0);
957 * @details The main logging loop
958 * @param[in] server The logger server
959 * @return 0 on success, else -errno
961 static int do_logger(struct logger* server)
963 struct sigaction action = {
964 .sa_handler = handle_signals,
967 sigemptyset(&action.sa_mask);
969 static const int handled_signals[] = { SIGINT, SIGTERM };
970 for (unsigned u = 0; u < NELEMS(handled_signals); ++u)
971 sigaction(handled_signals[u], &action, NULL);
973 bool use_lazy_polling = true;
974 while (g_logger_run) {
975 clock_gettime(CLOCK_MONOTONIC, &server->time.mono);
976 clock_gettime(CLOCK_REALTIME, &server->time.real);
978 if (server->lazy_polling_total >= 0) {
979 server->lazy_polling_total -= server->lazy_polling_sleep;
980 use_lazy_polling = (server->lazy_polling_total >= 0);
982 if (use_lazy_polling)
983 sleep_while_handling_socket(server, &server->epoll_socket, server->lazy_polling_sleep);
985 int r = handle_epoll_events(server, &server->epoll_common, server->epolltime * !use_lazy_polling);
989 service_all_readers(server);
990 qos_periodic_check(server);
993 /* ensure all logs are written no matter when the program was interrupted */
995 service_all_readers(server);
1001 * @brief Prepare socket data
1002 * @details Extracts initialisation data specific to each socket
1003 * @param[in] conf Config database
1004 * @param[out] data Socket init config data
1005 * @param[in] buf_name The name of the buffer the socket belongs to
1006 * @param[in] type The name of the buffer type
1007 * @return 0 on success, -errno on failure
1009 int prepare_socket_data(const struct log_config *conf, struct socket_config_data *data, char *buf_name, const char *type)
1011 char conf_key[MAX_CONF_KEY_LEN];
1014 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock", buf_name, type);
1017 const char * const path = log_config_get(conf, conf_key);
1019 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock_rights", buf_name, type);
1022 const char * const permissions_str = log_config_get(conf, conf_key);
1024 if (!permissions_str || !path)
1027 data->permissions = parse_permissions(permissions_str);
1028 if (data->permissions <= 0)
1031 strncpy(data->path, path, MAX_CONF_VAL_LEN - 1);
1037 * @brief Prepare buffer data
1038 * @details Extracts data specific for each buffer
1039 * @param[in] conf Config database
1040 * @param[out] data Buffer init config data
1041 * @param[in] buf_id Index of the buffer to work with
1042 * @return 0 on success, -errno on failure
1044 int prepare_buffer_data(const struct log_config *conf, struct buffer_config_data *data, log_id_t buf_id)
1046 char * const buf_name = log_name_by_id(buf_id);
1047 char * validity_check_ptr;
1048 char conf_key[MAX_CONF_KEY_LEN];
1051 r = prepare_socket_data(conf, &data->write_socket, buf_name, "write");
1055 r = prepare_socket_data(conf, &data->ctl_socket, buf_name, "ctl");
1059 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_size", buf_name);
1063 const char * const size_str = log_config_get(conf, conf_key);
1067 data->size = strtol(size_str, &validity_check_ptr, 10);
1068 if (*validity_check_ptr)
1070 if (data->size <= 0)
1077 * @brief Save logfile line
1078 * @detail Saves logfile config line in user_data list
1079 * @param[in] key Config entry key
1080 * @param[in] value Config entry value
1081 * @param[in] userdata Userdata
1083 void save_logfile_config(char const *key, char const *value, void *userdata)
1086 if (strncmp(key, CONF_PREFIX, sizeof CONF_PREFIX - 1))
1089 struct logger_config_data *data = (struct logger_config_data *)userdata;
1090 void *cmd = (void *)strdup(value);
1092 list_add(&data->logfile_configs, cmd);
1097 * @brief Initialize config data
1098 * @param[out] The data structure to fill with initial values
1100 void initialize_config_data(struct logger_config_data *data)
1102 memset(data, 0, sizeof *data);
1106 * @brief Prepare config data
1107 * @details Extracts relevant config data for logger initialisation
1108 * @param[out] data Parsed configuration
1109 * @return 0 on success, -errno on failure
1111 int prepare_config_data(struct logger_config_data *data)
1115 struct log_config conf;
1116 int ret = log_config_read(&conf);
1120 const dlogutil_sorting_order_e sort_by = get_order_from_config(&conf);
1122 int throttling_default = log_config_get_int(&conf, "logger_dev_throttling", LOGGER_DEVICE_THROTTLING_DEFAULT);
1123 const char *const dynamic_config_dir = log_config_get(&conf, DYNAMIC_CONFIG_CONF_KEY);
1125 const char * const backend = log_config_get(&conf, "backend");
1131 for (int i = 0; i < LOG_ID_MAX; i++) {
1132 char key[MAX_CONF_KEY_LEN];
1133 const int r = snprintf(key, sizeof key, "logger_dev_throttling_%s", log_name_by_id((log_id_t)i));
1137 g_backend.logger_device_throttling[i] = max_int(1, log_config_get_int(&conf, key, throttling_default));
1140 if (dynamic_config_dir && dynamic_config_dir[0] == '/') {
1141 data->dynamic_config_dir = strdup(dynamic_config_dir);
1142 if (!data->dynamic_config_dir) {
1147 data->dynamic_config_dir = NULL; // Technically unnecessary but no reason not to put it
1150 data->epoll_time = log_config_get_int(&conf, "epoll_time_ms", DEFAULT_EPOLL_TIME_MS);
1151 data->lazy_polling_total = log_config_get_int(&conf, "lazy_polling_total_ms", DEFAULT_LAZY_POLLING_TOTAL_MS);
1152 data->lazy_polling_sleep = log_config_get_int(&conf, "lazy_polling_sleep_ms", DEFAULT_LAZY_POLLING_SLEEP_MS);
1154 const char *const qos_file_path = log_config_get(&conf, "qos_file_path");
1155 data->qos_file_path = qos_file_path ? strdup(qos_file_path) : NULL;
1157 data->qos_limit_duration = log_config_get_int(&conf, "qos_refresh_rate_s", DEFAULT_QOS_LIMIT_DURATION_S);
1158 data->qos_max_throughput = log_config_get_int(&conf, "qos_max_throughput_logs", DEFAULT_QOS_THROUGHPUT_LOGS);
1159 data->qos_threshold = log_config_get_int(&conf, "qos_threshold_logs", DEFAULT_QOS_THRESHOLD_LOGS);
1160 data->qos_threshold_reapply = log_config_get_int(&conf, "qos_threshold_reapply_logs", DEFAULT_QOS_THRESHOLD_REAPPLY_LOGS);
1163 void (*func)(struct qos_module *qos, struct metrics_pid_aggr_info *infos, int count);
1165 } const qos_methods[] = {
1166 { qos_distribution_proportional_raw , "proportional_raw" },
1167 { qos_distribution_proportional_talmud, "proportional_talmud" },
1168 { qos_distribution_equal , "equal" },
1169 { qos_distribution_equal_dual , "equal_dual" },
1170 { qos_distribution_equal_multi , "equal_multi" },
1172 qos_distribution_func = qos_distribution_equal_multi; // default
1173 const char *const qos_method = log_config_get(&conf, "qos_method");
1175 for (int i = 0; i < NELEMS(qos_methods); ++i)
1176 if (!strcmp(qos_method, qos_methods[i].name))
1177 qos_distribution_func = qos_methods[i].func;
1179 const char *const first_time_file_path = log_config_get(&conf, "first_time_file_path");
1180 data->first_time_file_path = first_time_file_path ? strdup(first_time_file_path) : NULL;
1182 memset(data->is_buffer_enabled, 0, sizeof(data->is_buffer_enabled));
1183 if (!strcmp(backend, "pipe")) {
1184 data->is_buffer_enabled[LOG_ID_MAIN] =
1185 data->is_buffer_enabled[LOG_ID_RADIO] =
1186 data->is_buffer_enabled[LOG_ID_SYSTEM] =
1187 data->is_buffer_enabled[LOG_ID_APPS] = 1;
1188 g_backend.use_logger_by_default = false;
1189 } else if (!strcmp(backend, "logger")) {
1190 g_backend.use_logger_by_default = true;
1191 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
1192 const char *const logger_device = log_config_get(&conf, log_name_by_id(buf_id));
1194 strncpy(g_backend.logger_devices[buf_id], logger_device,
1195 NELEMS(g_backend.logger_devices[buf_id]) - 1);
1201 data->is_buffer_enabled[LOG_ID_KMSG] = log_config_get_boolean(&conf, "handle_kmsg", true);
1202 data->is_buffer_enabled[LOG_ID_SYSLOG] =
1203 dev_log_sock_get() >= 0 || log_config_get_boolean(&conf, "syslog_force", false);
1205 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
1206 if (data->is_buffer_enabled[buf_id]) {
1207 ret = prepare_buffer_data(&conf, data->buffers + buf_id, buf_id);
1210 data->buffers[buf_id].sort_by = sort_by;
1213 data->logfile_configs = NULL;
1214 log_config_foreach(&conf, save_logfile_config, data);
1217 log_config_free(&conf);
1221 static bool cond_string_free(void *ptr, void *user_data)
1228 static void free_config_data(struct logger_config_data *data)
1230 list_remove_if(&data->logfile_configs, NULL, cond_string_free);
1231 free(data->dynamic_config_dir);
1232 free(data->qos_file_path);
1233 free(data->first_time_file_path);
1237 * @brief Parse logfile line
1238 * @detail Parses a logfile config line
1239 * @param[in] key Config entry key
1240 * @param[in] value Config entry value
1241 * @param[in] userdata Userdata
1243 void parse_logfile_config(void *value, void *userdata)
1248 struct logger *server = (struct logger *) userdata;
1249 char *configline = (char *) value;
1251 __attribute__((cleanup(free_dlogutil_line_params))) struct dlogutil_line_params params;
1252 if (!initialize_dlogutil_line_params(¶ms, server->buf_params))
1255 get_dlogutil_line_params(configline, ¶ms);
1258 if (g_backend.use_logger_by_default && is_core_buffer(params.buf_id)) {
1259 r = create_logger_subreader_from_dlogutil_line(¶ms);
1261 struct reader_pipe *reader = NULL;
1262 r = create_reader_pipe_from_dlogutil_line(¶ms, server, &reader);
1264 add_reader_pipe(server, reader);
1269 printf("Warning: unable to add logutil reader for provided configuration. Ignoring.\n"
1270 " Config line: %s\n"
1271 " Reason given: %m\n",
1279 * @details Prints basic usage tips
1283 printf("Usage: %s [options]\n"
1284 "\t-h Show this help\n"
1285 "\t-b N Set the size of the log buffer (in bytes)\n"
1286 "\t-t N Set time between writes to file (in seconds)\n",
1287 program_invocation_short_name);
1292 * @details Parses execution parameters of the program
1293 * @param[in] argc Argument count
1294 * @param[in] argv Argument values
1295 * @param[out] b Buffering parameters
1296 * @return 0 or 1 on success, else -errno. Nonzero if the program is to close.
1298 static int parse_args(int argc, char **argv, struct buf_params *b)
1300 b->time = BUF_PARAM_TIME_DEFAULT;
1301 b->bytes = BUF_PARAM_BYTES_DEFAULT;
1303 __attribute__((cleanup(reset_getopt_internals))) int option;
1304 while ((option = getopt(argc, argv, "hb:t:")) != -1) {
1307 if (!isdigit(optarg[0]))
1309 b->time = clamp_int(atoi(optarg), BUF_PARAM_TIME_MIN, BUF_PARAM_TIME_MAX);
1312 if (!isdigit(optarg[0]))
1314 b->bytes = clamp_int(atoi(optarg), BUF_PARAM_BYTES_MIN, BUF_PARAM_BYTES_MAX);
1327 * @brief Finalize initialisation
1328 * @details Do misc stuff needed at the end of the initialisation
1329 * @param[in] data configuration dat to read logfiles config lines from
1330 * @param[in] server logger instance to configure
1331 * @return 0 on success, -errno on failure
1333 static int finalize_init(struct logger_config_data *data, struct logger *server)
1335 int r = sd_notify(0, "READY=1");
1339 // used to populate the first readers
1340 clock_gettime(CLOCK_MONOTONIC, &server->time.mono);
1341 clock_gettime(CLOCK_REALTIME, &server->time.real);
1343 //create files after resetting self privileges
1344 list_foreach(data->logfile_configs, server, parse_logfile_config);
1349 static void precreate_logctl_file(struct logger_config_data *data)
1351 char *logctl_file_path = NULL;
1352 if (asprintf(&logctl_file_path, "%s/%s", data->dynamic_config_dir, DYNAMIC_CONFIG_FILENAME) < 0)
1353 // This is worrying but unimportant
1356 int fd = open(logctl_file_path, O_RDONLY | O_CREAT, 0644);
1358 // Again, no big deal
1366 * @return 0 on success, nonzero on failure
1367 * @retval 1 Configuration error
1368 * @retval 2 Runtime error
1370 int main(int argc, char** argv)
1374 signal(SIGPIPE, SIG_IGN);
1376 r = reset_self_privileges();
1379 printf("Unable to drop privileges to build-time defaults (%m). Exiting.\n");
1380 return DLOG_EXIT_ERR_RUNTIME;
1383 struct logger_config_data data;
1384 initialize_config_data(&data);
1386 if ((r = parse_args(argc, argv, &data.buf_params)) != 0) {
1390 return DLOG_EXIT_SUCCESS; // --help option
1393 printf("Unable to parse command line args (%m). Exiting.\n");
1394 return DLOG_EXIT_ERR_CONFIG;
1397 if ((r = prepare_config_data(&data)) != 0) {
1399 printf("Unable to prepare config (%m). Exiting.\n");
1400 return DLOG_EXIT_ERR_CONFIG;
1403 precreate_logctl_file(&data);
1405 struct logger server;
1406 if ((r = logger_create(&data, &server)) < 0) {
1408 printf("Unable to initialize logger with provided configuration (%m). Exiting.\n");
1409 ret = DLOG_EXIT_ERR_CONFIG;
1413 if ((r = finalize_init(&data, &server)) < 0) {
1415 printf("Unable to finalize initialisation (%m). Exiting.\n");
1416 ret = DLOG_EXIT_ERR_CONFIG;
1420 if ((r = do_logger(&server)) < 0) {
1422 printf("Runtime failure (%m). Exiting.\n");
1423 ret = DLOG_EXIT_ERR_RUNTIME;
1427 ret = DLOG_EXIT_SUCCESS;
1430 free_config_data(&data);
1431 logger_free(&server);