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"
25 * @addtogroup DLOG_IMPLEMENTATION
27 * @defgroup DLOG_LOGGER Logger
28 * @brief Logger daemon
29 * @details The logger is the core component of the logging framework. It is responsible for collecting, processing and exposing logs.
33 // function prototypes
34 static int service_writer_socket(struct logger* server, struct writer* wr, struct epoll_event* event);
35 static int service_writer_pipe(struct logger* server, struct writer* wr, struct epoll_event* event);
36 int service_writer_kmsg(struct logger* server, struct writer* wr, struct epoll_event* event);
37 int service_writer_syslog(struct logger* server, struct writer* wr, struct epoll_event* event);
38 static int service_writer_handle_req_ctrl(struct logger *server, struct writer *wr, struct dlog_control_msg *msg);
39 static int service_writer_handle_req_pipe(struct logger *server, struct writer *wr, struct dlog_control_msg *msg);
40 void dispatch_event_writer(struct logger *server, struct epoll_event *event);
41 void dispatch_event_sock(struct logger *server, struct epoll_event *event);
42 static void dispatch_event_reader_sink(struct logger *server, struct epoll_event *event);
43 static void dispatch_event_reader_source(struct logger *server, struct epoll_event *event);
44 void reader_free(struct reader* reader);
45 static void logger_free(struct logger* l);
46 int socket_initialize(struct sock_data *sock, struct log_buffer *buffer, service_socket_t service_socket, struct socket_config_data *data);
48 /** global state when logger is not interrupted by any handled signals */
49 static volatile sig_atomic_t g_logger_run = 1;
52 int (*reader_init)(struct reader *reader, const char *buf_name, struct logger *server);
53 char logger_devices[LOG_ID_MAX][MAX_CONF_VAL_LEN];
54 int logger_device_throttling[LOG_ID_MAX];
60 * @brief Parse permissions
61 * @details Parse a string representation of permissions to the internal integral one
62 * @param[in] str The string representation
63 * @return The integer representation
65 int parse_permissions(const char * str)
71 return S_IWUSR | S_IWGRP | S_IWOTH; // 0222: everyone can write
73 parsed = strtol(str, & parse_safety, 8); // note, rights are octal
74 if (parse_safety != (str + strlen(str)))
79 // note that R and X are pretty useless, only W makes sense
80 if (parsed & 00001) ret |= S_IXOTH;
81 if (parsed & 00002) ret |= S_IWOTH;
82 if (parsed & 00004) ret |= S_IROTH;
83 if (parsed & 00010) ret |= S_IXGRP;
84 if (parsed & 00020) ret |= S_IWGRP;
85 if (parsed & 00040) ret |= S_IRGRP;
86 if (parsed & 00100) ret |= S_IXUSR;
87 if (parsed & 00200) ret |= S_IWUSR;
88 if (parsed & 00400) ret |= S_IRUSR;
89 if (parsed & 01000) ret |= S_ISVTX;
90 if (parsed & 02000) ret |= S_ISGID;
91 if (parsed & 04000) ret |= S_ISUID;
94 printf("Warning: useless bits in permissions %s!", str);
100 * @brief Get numerical ids for specified user and group
101 * @details Converts user and group strings to proper uid and gid identifiers
102 * @param[in] user The new user
103 * @param[in] group The new group
104 * @param[out] uid The uid for user
105 * @param[out] gid The numerical gid for group
106 * @return 0 on success, else -errno
108 int usergr2id(const char * user, const char * group, uid_t *uid, gid_t *gid)
110 struct passwd pwd, *ppwd;
111 struct group grp, *pgrp;
112 int bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
120 char *const buffer = (char *)alloca(bufsize);
122 if (getgrnam_r(user, &grp, buffer, bufsize, &pgrp))
127 if (getpwnam_r(group, &pwd, buffer, bufsize, &ppwd))
139 * @brief Reset privileges
140 * @details Resets privileges to those specified at build-time
141 * @return 0 on success, else -errno
143 int reset_self_privileges()
149 r = usergr2id(DLOG_SERVER_USER, DLOG_SERVER_GROUP, &uid, &gid);
153 if (getegid() != gid && setgid(gid) < 0)
155 if (geteuid() != uid && setuid(uid) < 0)
156 return -errno; // should never happen
162 * @brief Create a bound socket
163 * @details Creates a socket of given type under the given path
164 * @param[in] path The path to the socket
165 * @param[in] type Socket type (SOCK_DGRAM or SOCK_STREAM) with flags
166 * @return The socket FD, or negative errno
168 int bind_fd_create(const char* path, int type)
170 struct sockaddr_un server_addr;
173 sd = socket(AF_UNIX, type, 0);
177 memset(&server_addr, 0, sizeof(server_addr));
178 server_addr.sun_family = AF_UNIX;
179 strncpy(server_addr.sun_path, path, sizeof(server_addr.sun_path)-1);
180 unlink(server_addr.sun_path);
182 if (bind(sd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
193 * @brief Create a listening socket
194 * @details Creates a socket with given permissions under the given path
195 * @param[in] path The path to the socket
196 * @param[in] permissions File permissions (the internal representation)
197 * @return The socket FD, or negative errno
199 int listen_fd_create(const char* path, int permissions)
201 int sd = bind_fd_create(path, SOCK_STREAM);
206 if (chmod(path, permissions) < 0) // ideally, fchmod would be used, but that does not work
209 if (listen(sd, MAX_CONNECTION_Q) < 0)
220 * @brief Add given FD entity to logger event notification
221 * @details Uses epoll mechanism for notification of events
222 * @param[in] logger server owning epoll main loop
223 * @param[in] fd_entity file descriptor entity
224 * @return 0 on success, -errno on failure
226 int add_fd_entity(struct logger *logger, struct fd_entity *fd_entity)
231 int r = epoll_ctl(logger->epollfd, EPOLL_CTL_ADD, fd_entity->fd, &fd_entity->event);
240 * @brief Modify given FD entity to logger event notification
241 * @details Uses epoll mechanism for notification of events
242 * @param[in] logger server owning epoll main loop
243 * @param[in] fd_entity file descriptor entity
244 * @param[in] wanted_mask wanted event mask
245 * @return 0 on success, -errno on failure
247 int modify_fd_entity(const struct logger *logger, struct fd_entity *fd_entity, int wanted_mask)
252 if (fd_entity->fd < 0)
255 uint32_t pre = fd_entity->event.events;
256 if (pre == wanted_mask)
258 fd_entity->event.events = wanted_mask;
260 if (epoll_ctl(logger->epollfd, EPOLL_CTL_MOD, fd_entity->fd, &fd_entity->event) < 0) {
261 fd_entity->event.events = pre;
268 * @brief Remove given FD entity from logger event notification
269 * @details Uses epoll mechanism for notification of events
270 * @param[in] logger server owning epoll main loop
271 * @param[in] fd_entity file descriptor entity
272 * @return 0 on success, else -errno
274 int remove_fd_entity(struct logger *logger, struct fd_entity *fd_entity)
277 assert(logger->epollcnt > 0);
280 int r = epoll_ctl(logger->epollfd, EPOLL_CTL_DEL, fd_entity->fd, NULL);
289 * @brief Init fd entity to call given function with user data on event
290 * @details Initializes dispatch_event callback and user_data pointer
291 * @param[in] fd_entity file descriptor entity to initialize
292 * @param[in] dispatch_event callback function to dispatch an event to
293 * @param[in] user_data pointer to data to place in event structure when dispatch event is called
295 void init_fd_entity(struct fd_entity *fd_entity, dispatch_event_t dispatch_event, void *user_data)
298 *fd_entity = (struct fd_entity) {
299 .dispatch_event = dispatch_event,
300 .event = (struct epoll_event) {
301 .data = (epoll_data_t) { .ptr = user_data },
309 * @brief Set file descriptor to epoll entity for ready to read events
310 * @details Initializes fd and events mask in epoll entity
311 * @param[in] fd_entity file descriptor entity to initialize
312 * @param[in] fd file descriptor to set the entity with
314 void set_read_fd_entity(struct fd_entity *fd_entity, int fd)
318 fd_entity->event.events = EPOLLIN;
323 * @brief Set file descriptor to epoll entity for ready to write events
324 * @details Initializes fd and events mask in epoll entity
325 * @param[in] fd_entity file descriptor entity to initialize
326 * @param[in] fd file descriptor to set the entity with
328 void set_write_fd_entity(struct fd_entity *fd_entity, int fd)
333 fd_entity->event.events = EPOLLHUP; /* not EPOLLOUT - readers start dormant,
334                                      * get written to in atomic-like chunks,
335                                      * and only temporarily use EPOLLOUT if
336                                      * their pipe gets clogged mid-chunk */
341 * @brief Create a writer
342 * @details Create a writer structure
343 * @param[out] writer The newly-allocated writer
344 * @param[in] fd The FD writer initially belongs to
345 * @param[in] log_buffer The logging buffer
346 * @param[in] service_writer callback function for handling new data on writer descriptor FD
347 * @return 0 on success, -ENOMEM when out of memory
349 int writer_create(struct writer **writer, int fd, struct log_buffer *log_buffer,
350 service_writer_t service_writer, service_socket_t service_socket)
352 struct writer *w = (struct writer *)calloc(1, sizeof(struct writer));
356 init_fd_entity(&w->fd_entity, dispatch_event_writer, w);
357 set_read_fd_entity(&w->fd_entity, fd);
358 w->buf_ptr = log_buffer;
360 w->service_writer = service_writer;
361 w->service_socket = service_socket;
368 * @brief Dummy function placeholder that should not be called at all
369 * @details Use this function as a service socket callback for writers that handle other resources than sockets
370 * This function is temporary and only for testing purposes
371 * @param[in] server Unused
372 * @param[in] wr Unused
373 * @param[in] msg Unused
374 * @return Will not return - just raises SIGABRT signal
376 * @todo Remove this function after unification of evant handling functionality of writers
378 int service_socket_dummy(struct logger *server, struct writer *wr, struct dlog_control_msg *msg) // LCOV_EXCL_START
383 assert(0 && "This function should not be called");
388 * @brief Create kmsg writer
389 * @details Create the structure responsible for handling writing data from /dev/kmsg to given logging buffer
390 * @param[out] writer The newly-allocated writer
391 * @param[in] log_buffer The logging buffer
392 * @return 0 on success, -errno on failure
394 int create_kmsg_writer(struct writer ** writer, struct log_buffer *log_buffer)
396 int fd = open("/dev/kmsg", O_RDONLY | O_NONBLOCK);
400 int ret = writer_create(writer, fd, log_buffer, service_writer_kmsg, service_socket_dummy);
407 int systemd_sock_get(const char *path, int type)
410 int n = sd_listen_fds(0);
413 for (i = SD_LISTEN_FDS_START; sock_fd < 0 && i < SD_LISTEN_FDS_START + n; i++)
414 if (sd_is_socket_unix(i, type, -1, path, 0) > 0)
420 /* TODO: move the path to the configuration */
421 static const char dev_log_sock[] = "/run/dlog/dev-log";
422 static const char dev_log_link[] = "/dev/log";
424 int dev_log_sock_get()
426 return systemd_sock_get(dev_log_sock, SOCK_DGRAM);
429 int dev_log_sock_create()
431 int fd = bind_fd_create(dev_log_sock, SOCK_DGRAM);
433 unlink(dev_log_link);
434 if (symlink(dev_log_sock, dev_log_link) == -1) {
443 * @brief Create syslog writer
444 * @details Create the structure responsible for handling writing data from syslog to given logging buffer
445 * @param[out] writer The newly-allocated writer
446 * @param[in] log_buffer The logging buffer
447 * @return 0 on success, -errno on failure
449 int create_syslog_writer(struct writer ** writer, struct log_buffer *log_buffer)
451 int fd = dev_log_sock_get();
453 fd = dev_log_sock_create();
457 int err = fd_set_flags(fd, O_NONBLOCK);
463 int ret = writer_create(writer, fd, log_buffer, service_writer_syslog, service_socket_dummy);
471 * @brief Close socket that was initialized using socket_initialize function
472 * @details Closes socket entity fd
473 * @param[in] sock socet data to close
475 void socket_close(struct sock_data *sock)
478 if (sock->fd_entity.fd >= 0)
479 close(sock->fd_entity.fd);
483 * @brief Create buffer
484 * @details Allocate a buffer structure
485 * @param[out] lb The newly-allocated buffer
486 * @param[in] buf_id The buffer ID
487 * @param[in] data Buffer config data
488 * @return 0 on success, -errno on failure
490 static int buffer_create(struct log_buffer **log_buffer, log_id_t buf_id, struct buffer_config_data *data)
493 struct log_buffer *lb = calloc(1, sizeof(*lb));
499 lb->log_storage = log_storage_create(data->size, data->sort_by);
500 if (!lb->log_storage) {
506 r = socket_initialize(&lb->sock_ctl, lb, service_writer_handle_req_ctrl, &data->ctl_socket);
508 log_storage_free(lb->log_storage);
513 r = socket_initialize(&lb->sock_wr, lb, service_writer_handle_req_pipe, &data->write_socket);
515 socket_close(&lb->sock_ctl);
516 log_storage_free(lb->log_storage);
526 * @brief Free reader given in ptr
527 * @details Use this function when deleting all readers in the list
528 * @param[in] ptr pointer to the reader
529 * @param[in] user_data pointer to the logger to remove readers waiting for an event
530 * @return always true (the reader is to be removed)
532 static bool cond_reader_free(void *ptr, void *user_data)
534 struct reader *reader = (struct reader *)ptr;
535 struct logger *logger = (struct logger *)user_data;
537 if (reader->fd_entity_sink.fd >= 0)
538 remove_fd_entity(logger, &reader->fd_entity_sink);
539 if (reader->fd_entity_source.fd >= 0)
540 remove_fd_entity(logger, &reader->fd_entity_source);
547 * @details Deallocate a buffer
548 * @param[in] buffer The buffer to deallocate
549 * @param[in] logger The server to remove buffer readers from fd loop
551 static void buffer_free(struct log_buffer *buffer, struct logger *logger)
555 list_remove_if(&buffer->readers, logger, cond_reader_free);
557 socket_close(&buffer->sock_ctl);
558 socket_close(&buffer->sock_wr);
560 log_storage_free(buffer->log_storage);
565 uint64_t reader_buffered_space(const struct reader *reader)
568 assert(reader->buf_ptr);
569 return log_storage_reader_get_ready_bytes(reader->log_storage_reader);
572 int reader_is_bufferable(const struct reader *reader)
575 return reader->buf_ptr && reader->file.path != NULL;
578 int reader_ms_since(const struct reader *reader, struct timespec *ts)
580 return (ts->tv_sec - reader->last_read_time.tv_sec) * 1000 + (ts->tv_nsec - reader->last_read_time.tv_nsec) / 1000000;
583 int reader_should_buffer(struct reader *reader, const struct buf_params *buf_params, struct timespec now)
588 if (!reader_is_bufferable(reader))
591 if (reader_buffered_space(reader) < (uint64_t)buf_params->bytes && reader_ms_since(reader, &now) < (buf_params->time * 1000))
594 reader->last_read_time = now;
599 * @brief Append to buffer
600 * @details Appends an entry to the buffer
601 * @param[in] s The logger server
602 * @param[in] entry The entry to append
603 * @param[in] b The buffer whither to append
605 int buffer_append(const dlogutil_entry_s *entry, struct log_buffer *b)
607 if (!log_storage_add_new_entry(b->log_storage, entry))
613 * @brief FD limit handler
614 * @details Checks whether the FD limit was reached and leaves logs about it if so
615 * @param[in] server The logger server
616 * @param[in] err errno from the call that failed to create an FD
618 static void check_if_fd_limit_reached(struct logger *server, int err)
622 if (err != ENFILE && err != EMFILE)
625 printf("ERROR: dlog_logger fd limit reached!\n");
627 /* pick one representative buffer to send the log to;
628 * no point spamming all the buffers, especially since
629 * default dlogutil invocations display 3 buffers so
630 * it would appear multiple times */
631 struct log_buffer *const buf = server->buffers[LOG_ID_MAIN];
635 struct dlogutil_entry_with_msg entry;
636 create_pipe_message(&entry,
637 DLOG_FATAL, /* not really FATAL, but since we're at the FD limit
638              * there are thousands of logging programs so this one
639              * would likely get lost in the flood since developers
640              * tend to overuse ERROR (and FATAL is the one above) */
642 "\x1b[31m DLOG DAEMON FD LIMIT REACHED \x1b[0m" // make it stand out
644 if (buffer_append(&entry.header, buf))
645 printf("ERROR: not enough memory either, please check platform settings as the daemon is seriously resource-starved!\n");
648 static int reader_print_out_single_log(struct reader *reader, const dlogutil_entry_s *dlogutil_entry)
651 assert(reader->buf_ptr);
652 assert(dlogutil_entry);
654 if (!log_should_print_line(reader->filter, dlogutil_entry))
657 if (reader->file.path) {
658 logfile_write_with_rotation(dlogutil_entry, &reader->file, reader->buf_ptr->sort_by);
662 const char *tag = dlogutil_entry->msg + 1;
666 int r = write(reader->file.path ? reader->file.fd : reader->fd_entity_sink.fd, dlogutil_entry, dlogutil_entry->len);
671 /* The pipe is just clogged, this is not an actual error.
672 * We own the entry so it needs to be saved for later. */
676 reader->file.size += r;
677 if (r < dlogutil_entry->len) {
678 reader->partial_log_size = dlogutil_entry->len - r;
679 memcpy(reader->partial_log, ((char *)dlogutil_entry) + r, reader->partial_log_size);
681 } else if (logfile_rotate_needed(&reader->file) > 0) {
682 logfile_do_rotate(&reader->file);
689 * @brief Print out logs
690 * @details Make sure the reader is up to date on printed logs
691 * @param[in] reader The reader to read the data
692 * @param[in] server The logger server
693 * @return 0 if data remains for the next iteration, 1 if the buffer is to be removed, else -1
695 int print_out_logs(struct reader *reader)
699 assert(reader->buf_ptr);
703 if (reader->partial_log_size) {
704 r = write(reader->fd_entity_sink.fd, reader->partial_log, reader->partial_log_size);
706 return r != 0 && errno != EAGAIN;
708 if (r < reader->partial_log_size) {
709 reader->partial_log_size -= r;
710 memmove(reader->partial_log, reader->partial_log + r, reader->partial_log_size);
714 reader->partial_log_size = 0;
717 while (log_storage_reader_is_new_entry_available(reader->log_storage_reader)) {
718 const dlogutil_entry_s* ple = (const dlogutil_entry_s *)log_storage_reader_get_new_entry(reader->log_storage_reader);
722 switch (reader_print_out_single_log(reader, ple)) {
723 case 0: /* nothing more to do, let's do next loop */
726 case 1: /* error after which we need to end the reader */
729 default: /* writing error, bounce out */
734 if (reader->dumpcount)
743 * @brief Writer close FD
744 * @details Close a writer's connections
745 * @param[in] server The logger server
746 * @param[in] wr The writer whose connections to close
748 void writer_close_fd(struct logger* server, struct writer* wr)
751 remove_fd_entity(server, &wr->fd_entity);
752 close(wr->fd_entity.fd);
757 * @details Deallocate a writer
758 * @param[in] w The writer to deallocate
760 static void writer_free(struct writer *w, struct logger *logger)
762 writer_close_fd(logger, w);
767 * @brief Free a reader
768 * @details Deallocates a reader
769 * @param[in] reader The reader to free
771 void reader_free(struct reader* reader)
776 if (reader->fd_entity_sink.fd >= 0)
777 close(reader->fd_entity_sink.fd);
778 if (reader->fd_entity_source.fd >= 0)
779 close(reader->fd_entity_source.fd);
780 logfile_free(&reader->file);
782 log_filter_free(reader->filter);
783 if (reader->log_storage_reader)
784 log_storage_release_reader(reader->log_storage_reader);
789 * @brief Service reader file
790 * @details Handles readers reading directly from file
791 * @param[in] reader The reader to service
792 * @return 0 on success, else an errno value
793 * @return 1 if the reader is to be removed, 0 if kept, -errno on error
795 int service_reader_file(struct reader* reader)
799 struct dlogutil_entry_with_msg entry;
800 static char buffer[sizeof entry + 1];
801 buffer[sizeof buffer - 1] = '\0';
803 /* The devices for both KMSG and Android Logger only return one log per read().
804 * So using an 'if' here would be wasteful and, more importantly, too slow in the case where other logs come in.
805 * However, with an unlimited loop, if there are extreme amounts of logs incoming,
806 * the loop handles them slower than they come so the program stays in the loop
807 * for a very long time, starving all other log sources. Using a limited loop
808 * makes sure that the daemon works efficiently in the usual case while preventing
809 * starvation under heavy load. */
810 int max_loop_iterations = g_backend.logger_device_throttling[reader->buf_id];
811 while (max_loop_iterations--) {
812 int r = TEMP_FAILURE_RETRY(read(reader->fd_entity_source.fd, buffer, sizeof buffer - 1));
816 if (errno == EAGAIN) // no data left in the buffer
822 parse_androidlogger_message((struct android_logger_entry *) buffer, &entry.header, r);
823 add_recv_timestamp(&entry.header);
825 if (!log_should_print_line(reader->filter, &entry.header))
828 logfile_write_with_rotation(&entry.header, &reader->file, DLOGUTIL_SORT_SENT_REAL);
835 void reader_notify_losing_log(const dlogutil_entry_s *le, void *reader_)
837 struct reader *reader = reader_;
840 reader_print_out_single_log(reader, (dlogutil_entry_s *)le);
844 * @brief Add reader to log buffer
845 * @details Adds a reader to the log buffers reader list
846 * @param[in] log_buffer The buffer whither to add the reader
847 * @param[in] reader The reader to add to the buffer
848 * @return 0 on success, -ENOMEM on memory allocation error
850 int add_buffer_reader(struct log_buffer *buffer, struct reader *reader)
855 reader->log_storage_reader = log_storage_new_reader(buffer->log_storage,
856 reader->dumpcount, reader->monitor, reader_notify_losing_log, reader);
858 if (!reader->log_storage_reader)
861 return list_add(&buffer->readers, reader) ? 0 : -ENOMEM;
865 * @brief Add reader to server
866 * @details Adds a reader to the server's reader list
867 * @param[in] server The server whither to add the reader
868 * @param[in] reader The reader to add to the server
869 * @return 0 on success, -EINVAL if related buffer not enabled or invalid reader type given
870 * -ENOMEM on memory allocation error
872 static int add_reader(struct logger *server, struct reader *reader)
877 if (reader->fd_entity_sink.fd >= 0) {
878 /* Readers who write to file have no sink FD entity (or, strictly
879 * speaking, they do have one but it is not filled) since a file
880 * is not eligible to be added to epoll. However, the entity primarily
881 * serves to handle pipes getting clogged mid-write (which cannot
882 * happen for files) and is not involved in starting a write,
883 * which is handled by the source FD entity, not sink (and which is
884 * also done periodically for all readers anyway regardless
885 * of whether they've been added to epoll or not). The other use
886 * case for epoll - the one where connection FDs leak for unused
887 * buffers - is not a problem here because the daemon is not
888 * supposed to ever stop writing to files. */
890 int r = add_fd_entity(server, &reader->fd_entity_sink);
896 if (reader->buf_ptr) {
897 ret = add_buffer_reader(reader->buf_ptr, reader);
903 assert(reader->fd_entity_source.fd >= 0);
904 ret = add_fd_entity(server, &reader->fd_entity_source);
908 if (!list_add(&server->extra_readers, reader)) {
909 remove_fd_entity(server, &reader->fd_entity_source);
917 if (reader->fd_entity_sink.fd >= 0)
918 remove_fd_entity(server, &reader->fd_entity_sink);
923 int reader_init_for_pipe(struct reader *reader, const char *buf_name, struct logger *server)
929 reader->service_reader = print_out_logs;
931 log_id_t buf_id = log_id_by_name(buf_name);
932 if (buf_id == LOG_ID_INVALID)
935 reader->buf_ptr = server->buffers[buf_id];
936 reader->buf_id = buf_id;
937 return (reader->buf_ptr ? 0 : -EINVAL);
940 int reader_init_for_logger(struct reader *reader, const char *buf_name, struct logger *server)
946 if (!strcmp(buf_name, "kmsg") || !strcmp(buf_name, "syslog"))
947 return reader_init_for_pipe(reader, buf_name, server);
949 reader->service_reader = service_reader_file;
951 log_id_t buf_id = log_id_by_name(buf_name);
952 if (buf_id == LOG_ID_INVALID)
955 assert(buf_id >= 0 && (unsigned) buf_id < NELEMS(g_backend.logger_devices));
956 char const *config_list = g_backend.logger_devices[buf_id];
957 if (strlen(config_list) == 0)
959 reader->buf_id = buf_id;
962 int ret = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &read_fd);
966 set_read_fd_entity(&reader->fd_entity_source, read_fd);
967 ret = add_fd_entity(server, &reader->fd_entity_source);
976 static int create_fifo_fds(struct logger *server, int fifo_id, int *write_fd, int *read_fd, bool dump)
982 if (snprintf(fifo_path, sizeof fifo_path, "/run/dlog/priv/fifo/%d", fifo_id) < 0)
985 if (mkfifo(fifo_path, 0600) < 0) {
986 assert(errno != EEXIST);
992 *read_fd = open(fifo_path, O_RDONLY | O_NONBLOCK);
994 check_if_fd_limit_reached(server, errno);
999 *write_fd = open(fifo_path, O_WRONLY | O_NONBLOCK);
1000 if (*write_fd < 0) {
1001 check_if_fd_limit_reached(server, errno);
1007 /* Speed up dumping dlogutils by increasing their pipe size,
1008 * as otherwise this pipe's size becomes a major bottleneck.
1010 * Continuous connections don't really care if the initial
1011 * burst of "historic" logs is slow and the following flow
1012 * of logs is just fine with a small pipe. Meanwhile they
1013 * live for a long time during which they would take away
1014 * from the valuable total pipe size. */
1016 if (fcntl(*write_fd, F_SETPIPE_SZ, DUMPING_READER_PIPE_SIZE) < 0) {
1017 /* Ignore; this is just a performance optimisation
1018 * and doesn't affect functionality so while errors
1019 * are worrisome they not a big deal or something
1020 * we can do anything about, at any rate. */
1029 * @brief Parse a command line
1030 * @details Creates a reader from a parsed command line
1031 * @param[in] cmdl The command line string
1032 * @param[in] wr The writer who sent the line (NULL if internal)
1033 * @param[in] server The server
1034 * @param[out] rd The new reader
1035 * @return 0 on success, else -errno
1037 static int parse_command_line(const char *cmdl, struct writer *wr, struct logger *server, struct reader **rd)
1040 // wr optional: NULL means created by config
1045 int option, argc = 0;
1050 struct reader *reader;
1053 snprintf(cmdline, sizeof(cmdline), "%s", cmdl);
1055 reader = (struct reader *)calloc(1, sizeof(struct reader));
1061 tok = strtok_r(cmdline, DELIMITER, &tok_sv);
1062 if (!tok || strcmp(tok, "dlogutil")) {
1067 while (tok && (argc < NELEMS(argv))) {
1069 tok = strtok_r(NULL, DELIMITER, &tok_sv);
1072 init_fd_entity(&reader->fd_entity_sink, dispatch_event_reader_sink, reader);
1073 init_fd_entity(&reader->fd_entity_source, dispatch_event_reader_source, reader);
1075 logfile_init(&reader->file);
1077 reader->filter = log_filter_new();
1078 if (!reader->filter)
1081 reader->buf_ptr = NULL;
1082 reader->buf_id = -1;
1083 reader->dumpcount = false;
1084 reader->monitor = false;
1085 reader->partial_log_size = 0;
1086 reader->service_reader = NULL;
1087 reader->log_storage_reader = NULL;
1088 clock_gettime(CLOCK_MONOTONIC, &reader->last_read_time);
1090 static const struct option long_options[] = {
1091 {"tid", required_argument, NULL, 0},
1092 {"pid", required_argument, NULL, 1},
1096 while ((option = getopt_long(argc, argv, "cdt:gsf:r:n:v:b:mu:", long_options, NULL)) != -1) {
1101 reader->dumpcount = true;
1104 reader->monitor = true;
1108 /* Do not trust writer-based readers (only config-based).
1109 * The control socket's privilege checks are fairly lenient
1110 * so this prevents people from asking us to overwrite
1111 * some potentially important files at logger privilege.
1113 * At some point it would be good to be able to skip the
1114 * middleman and become able to write to a file directly
1115 * though. The daemon should become able to receive an
1116 * opened file descriptor from a writer. */
1121 retval = logfile_set_path(&reader->file, optarg);
1126 assert(g_backend.reader_init);
1127 retval = g_backend.reader_init(reader, optarg, server);
1132 if (sscanf(optarg, "%zu", &reader->file.rotate_size_kbytes) != 1)
1136 if (sscanf(optarg, "%zu", &reader->file.max_rotated) != 1)
1140 reader->file.format.format = log_format_from_string(optarg);
1144 dlogutil_filter_options_set_filterspec(reader->filter, "*:s");
1148 if (sscanf(optarg, "%d", &tid) != 1 || dlogutil_filter_options_set_tid(reader->filter, tid))
1154 if (sscanf(optarg, "%d", &pid) != 1 || dlogutil_filter_options_set_pid(reader->filter, pid))
1158 case '?': // invalid option or missing argument
1162 // everything else gets handled in util directly
1167 // dump + monitor = continuous
1168 if (reader->monitor && reader->dumpcount) {
1169 reader->dumpcount = false;
1170 reader->monitor = false;
1173 if (wr && wr->buf_ptr) {
1174 reader->service_reader = print_out_logs;
1175 reader->buf_ptr = wr->buf_ptr;
1178 if (reader->service_reader == NULL) {
1184 while (optind < argc)
1185 dlogutil_filter_options_set_filterspec(reader->filter, argv[optind++]);
1187 dlogutil_filter_options_set_filterspec(reader->filter, "*:D");
1189 if ((reader->fd_entity_source.fd < 0) && !reader->buf_ptr) {
1194 if (reader->file.path != NULL) {
1195 retval = logfile_open(&reader->file);
1199 int write_fd = -1, read_fd = -1;
1200 retval = create_fifo_fds(server, wr->fd_entity.fd, &write_fd, &read_fd, reader->dumpcount);
1204 set_write_fd_entity(&reader->fd_entity_sink, write_fd);
1205 retval = send_pipe(wr->fd_entity.fd, read_fd);
1214 /* recycle for further usage */
1221 int r = send_dlog_reply(wr->fd_entity.fd, DLOG_REQ_HANDLE_LOGUTIL, DLOG_REQ_RESULT_ERR, NULL, 0);
1223 printf("ERROR: both parse_command_line() and send_dlog_reply() failed\n");
1226 reader_free(reader);
1233 * @brief Service util request
1234 * @details Handle a request from util
1235 * @param[in] server The logger server
1236 * @param[in] wr The writer who sent the request
1237 * @param[in] msg The message containing the request
1238 * @return 0 on success, else -errno
1240 static int service_writer_handle_req_util(struct logger* server, struct writer* wr, struct dlog_control_msg* msg)
1244 // check request type, that should be always DLOG_REQ_HANDLE_LOGUTIL
1245 // as dispatched by service_writer_handle_req_ctrl handler
1246 // don't assert for compatibility with service_writer_handle_req_pipe
1247 // and possible mistakes in the future that would be hard to track
1248 if (msg->request != DLOG_REQ_HANDLE_LOGUTIL)
1251 if (msg->length <= sizeof(struct dlog_control_msg) ||
1252 msg->length > sizeof(struct dlog_control_msg) + MAX_LOGGER_REQUEST_LEN)
1255 if (msg->data[msg->length - sizeof(struct dlog_control_msg)] != 0)
1259 int r = parse_command_line(msg->data, wr, server, &rd);
1264 assert(rd->buf_ptr);
1266 r = add_reader(server, rd);
1271 if (wr->readed > msg->length) {
1272 wr->readed -= msg->length;
1273 memmove(wr->buffer, wr->buffer + msg->length, wr->readed);
1280 static int service_writer_handle_req_getsize(struct logger *server, struct writer *wr, struct dlog_control_msg *msg)
1285 assert(msg->request == DLOG_REQ_GETSIZE);
1287 uint32_t buf_size = log_storage_get_capacity(wr->buf_ptr->log_storage);
1289 return send_dlog_reply(wr->fd_entity.fd, DLOG_REQ_GETSIZE, DLOG_REQ_RESULT_OK, &buf_size, sizeof buf_size);
1293 * @brief Service clear request
1294 * @details Handle a clear-buffer request
1295 * @param[in] server The logger server
1296 * @param[in] wr The writer who sent the request
1297 * @param[in] msg The message containing the request
1298 * @return 0 on success, else -errno
1300 static int service_writer_handle_req_clear(struct logger* server, struct writer* wr, struct dlog_control_msg* msg)
1305 // check request type, that should be always DLOG_REQ_CLEAR
1306 // as dispatched by service_writer_handle_req_ctrl handler
1307 // don't assert for compatibility with service_writer_handle_req_pipe
1308 // and possible mistakes in the future that would be hard to track
1309 if (msg->request != DLOG_REQ_CLEAR)
1312 if (msg->length != (sizeof(struct dlog_control_msg)))
1315 if (!wr || !wr->buf_ptr)
1318 log_storage_clear(wr->buf_ptr->log_storage);
1320 if (wr->readed > msg->length) {
1321 wr->readed -= msg->length;
1322 memmove(wr->buffer, wr->buffer + msg->length, wr->readed);
1330 * @brief Service control request
1331 * @details Handle a clear-buffer or util request in respect to msg request type
1332 * @param[in] server The logger server
1333 * @param[in] wr The writer who sent the request
1334 * @param[in] msg The message containing the request
1335 * @return 0 on success, else -errno
1337 static int service_writer_handle_req_ctrl(struct logger *server, struct writer *wr, struct dlog_control_msg *msg)
1341 switch (msg->request) {
1342 case DLOG_REQ_CLEAR:
1343 return service_writer_handle_req_clear(server, wr, msg);
1344 case DLOG_REQ_HANDLE_LOGUTIL:
1345 return service_writer_handle_req_util(server, wr, msg);
1346 case DLOG_REQ_GETSIZE:
1347 return service_writer_handle_req_getsize(server, wr, msg);
1354 * @brief Service a pipe acquisition request
1355 * @details Handle a pipe request
1356 * @param[in] server The logger server
1357 * @param[in] wr The writer who sent the request
1358 * @param[in] msg The message containing the request
1359 * @return 0 on success, else -errno
1361 static int service_writer_handle_req_pipe(struct logger* server, struct writer* wr, struct dlog_control_msg* msg)
1367 // check request type given by user
1368 // don't assert that as the message is not parsed before
1369 if (msg->request != DLOG_REQ_PIPE)
1372 if (msg->length != sizeof(struct dlog_control_msg))
1376 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
1377 check_if_fd_limit_reached(server, errno);
1381 if (fcntl(pipe_fd[1], F_SETPIPE_SZ, PIPE_REQUESTED_SIZE) < 0) {
1382 /* Ignore failures. This call is just a performance optimisation
1383 * and doesn't affect functionality; we can't do anything about
1384 * an error anyway. */
1390 struct fd_entity pipe_entity = wr->fd_entity;
1391 set_read_fd_entity(&pipe_entity, pipe_fd[0]);
1392 r = add_fd_entity(server, &pipe_entity);
1396 r = send_pipe(wr->fd_entity.fd, pipe_fd[1]);
1401 writer_close_fd(server, wr);
1402 wr->service_writer = service_writer_pipe;
1403 wr->fd_entity = pipe_entity;
1408 remove_fd_entity(server, &pipe_entity);
1418 * @brief Service a socket request
1419 * @details Handle a socket request
1420 * @param[in] server The logger server
1421 * @param[in] wr The writer who sent the request
1422 * @param[in] event The event containing the request
1423 * @return 0 on success, else -errno
1425 static int service_writer_socket(struct logger* server, struct writer* wr, struct epoll_event* event)
1430 struct dlog_control_msg* const msg = (struct dlog_control_msg*) wr->buffer;
1433 if (event->events & EPOLLIN)
1434 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
1436 if ((r == 0 || r == -1) && event->events & EPOLLHUP)
1443 /* The socket is SOCK_STREAM (see `listen_fd_create`), so one message
1444 * could be split into chunks returned across multiple read() calls. */
1445 if (wr->readed < sizeof(msg->length)
1446 || wr->readed < msg->length)
1447 goto dont_process_yet_and_read_more_data;
1449 assert(wr->service_socket);
1450 r = wr->service_socket(server, wr, msg);
1454 dont_process_yet_and_read_more_data:
1455 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
1456 } while (r > 0 || ((wr->readed >= sizeof(msg->length) && wr->readed >= msg->length)));
1458 return (r >= 0 || errno == EAGAIN) ? 0 : r;
1462 * @brief Service pipe log data
1463 * @details Handle log messages incoming through a pipe
1464 * @param[in] server The logger server
1465 * @param[in] wr The writer who sent the logs
1466 * @param[in] event The event associated with the data
1467 * @return 0 on success, else -errno
1469 static int service_writer_pipe(struct logger *server, struct writer *wr, struct epoll_event *event)
1471 if (event->events & EPOLLIN) {
1472 int r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
1474 if (r == -1 && errno == EAGAIN)
1476 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
1483 struct pipe_logger_entry *const ple = (struct pipe_logger_entry *const)wr->buffer;
1484 while ((wr->readed >= sizeof(ple->len)) && (ple->len <= wr->readed)) {
1485 const int payload_size = ple->len - sizeof *ple;
1486 if (payload_size < 0 || payload_size > LOG_MAX_PAYLOAD_SIZE)
1489 struct dlogutil_entry_with_msg lem;
1490 parse_pipe_message(ple, &lem.header, ple->len);
1491 add_recv_timestamp(&lem.header);
1492 fixup_pipe_msg(&lem, payload_size);
1493 r = buffer_append(&lem.header, wr->buf_ptr);
1494 wr->readed -= ple->len;
1495 memmove(wr->buffer, wr->buffer + ple->len, sizeof wr->buffer - ple->len);
1500 } else if (event->events & EPOLLHUP)
1507 * @brief Service /dev/kmsg
1508 * @details Read from the /dev/kmsg device
1509 * @param[in] server The logger server
1510 * @param[in] wr The writer who sent the request
1511 * @param[in] event The relevant event
1512 * @return 0 on success, else -errno
1514 int service_writer_kmsg(struct logger* server, struct writer* wr, struct epoll_event* event)
1517 if (event->events & EPOLLHUP)
1519 if (!(event->events & EPOLLIN))
1522 /* The KMSG device returns just 1 log per read() so it is done in a loop.
1523 * In theory this could starve everything else out if logs appeared faster
1524 * than the daemon could process them, which would then necessitate some
1525 * sort of throttling. In practice, KMSG doesn't really get flooded with
1526 * logs the same way Android Logger devices are so the throttling is mostly
1527 * there because we get it for free anyway and consistency doesn't hurt. */
1529 int max_loop_iterations = g_backend.logger_device_throttling[LOG_ID_KMSG];
1530 while (max_loop_iterations--) {
1531 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
1533 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
1535 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
1542 wr->buffer[r] = '\0';
1543 struct dlogutil_entry_with_msg lem;
1544 if (parse_kmsg_message(wr->buffer, &lem, r)) {
1545 // don't signal an error: KMSG writer is too important to remove; besides, it would not get fixed that way.
1548 add_recv_timestamp(&lem.header);
1549 r = buffer_append(&lem.header, wr->buf_ptr);
1558 * @brief Service reader given in ptr
1559 * @details Use this function when servicing all readers in the list
1560 * @param[in] ptr pointer to the reader
1561 * @param[in] user_data pointer to the logger to add readers waiting for an event
1562 * @return true if the reader is to be removed
1564 static bool cond_service_reader(void *ptr, void *user_data)
1568 struct reader *reader = (struct reader *)ptr;
1569 struct logger *logger = (struct logger *)user_data;
1571 if (!logger->exiting && reader_should_buffer(reader, &logger->buf_params, logger->now))
1574 assert(reader->service_reader);
1575 int r = reader->service_reader(reader);
1578 if (reader->fd_entity_sink.fd >= 0)
1579 remove_fd_entity(logger, &reader->fd_entity_sink);
1580 if (reader->fd_entity_source.fd >= 0)
1581 remove_fd_entity(logger, &reader->fd_entity_source);
1582 reader_free(reader);
1586 /* `service_reader()` returns -1 if everything was flushed, or 0 if
1587 * a mild error happened that can be recovered from simply by waiting,
1588 * the prime example being the pipe getting clogged. As soon as the
1589 * reader is available again, we'd like to know about it to ensure
1590 * logs are flushed as quickly as possible, which is why the EPOLLOUT.
1592 * On the other hand, we don't want to remove readers from epoll even
1593 * if they successfully flushed and have no logs to wait for. Consider
1594 * the case where a buffer is unused (for example through libdlog's
1595 * buffer disabling feature). If we relied on receiving an error on
1596 * calling `write()` to learn that the connection had been closed,
1597 * we would never learn about it because there would be no incoming
1598 * logs to trigger the flush and so any FDs representing connections
1599 * to such buffer would leak until a log finally arrived (which could
1600 * be never). This is why waiting is also done on EPOLLHUP. */
1601 if (modify_fd_entity(logger, &reader->fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) {
1602 /* ignore, can't really happen and it's not
1603 * like we can do anything about it either */
1610 * @brief Dispatch reader event
1611 * @details Receives and handles an event
1612 * @param[in] server The logger server
1613 * @param[in] event The received event
1614 * @param[in] offset The offset of the event fd entity into the reader struct
1616 static void dispatch_event_reader_common(struct logger *server, struct epoll_event *event, size_t offset)
1619 struct reader *reader = (struct reader *)(((char *)event->data.ptr) - offset);
1623 if (event->events & (EPOLLHUP | EPOLLERR)) {
1624 list_remove(&reader->buf_ptr->readers, reader);
1625 list_remove(&server->extra_readers, reader);
1626 if (reader->fd_entity_sink.fd >= 0)
1627 remove_fd_entity(server, &reader->fd_entity_sink);
1628 if (reader->fd_entity_source.fd >= 0)
1629 remove_fd_entity(server, &reader->fd_entity_source);
1630 reader_free(reader);
1634 assert(reader->service_reader);
1635 int r = reader->service_reader(reader);
1637 if (reader->fd_entity_sink.fd >= 0)
1638 remove_fd_entity(server, &reader->fd_entity_sink);
1639 if (reader->fd_entity_source.fd >= 0)
1640 remove_fd_entity(server, &reader->fd_entity_source);
1644 static void dispatch_event_reader_sink(struct logger *server, struct epoll_event *event)
1646 dispatch_event_reader_common(server, event, offsetof(struct reader, fd_entity_sink));
1649 static void dispatch_event_reader_source(struct logger *server, struct epoll_event *event)
1651 dispatch_event_reader_common(server, event, offsetof(struct reader, fd_entity_source));
1655 * @brief Service syslog
1656 * @details Read from the syslog socket
1657 * @param[in] server The logger server
1658 * @param[in] wr The writer who sent the request
1659 * @param[in] event The relevant event
1660 * @return 0 on success, else -errno
1662 int service_writer_syslog(struct logger* server, struct writer* wr, struct epoll_event* event)
1664 if (event->events & EPOLLHUP)
1666 if (!(event->events & EPOLLIN))
1669 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
1671 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
1673 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
1680 wr->buffer[r] = '\0';
1682 struct dlogutil_entry_with_msg lem;
1683 if (parse_syslog_datagram(wr->buffer, r + 1, &lem.header)) {
1684 /* don't return parse error as writers are removed then */
1688 add_recv_timestamp(&lem.header);
1689 return buffer_append(&lem.header, wr->buf_ptr);
1693 * @brief Service all readers
1694 * @details Update all readers with latest data
1695 * @param[in] server The logger server
1696 * @param[in] force_push Whether to force logs to be pushed to the readers
1698 static void service_all_readers(struct logger *server)
1700 for (int i = 0; i < LOG_ID_MAX; i++) {
1701 struct log_buffer *const buffer = server->buffers[i];
1705 list_remove_if(&buffer->readers, server, cond_service_reader);
1707 list_remove_if(&server->extra_readers, server, cond_service_reader);
1711 * @brief Initialize a socket
1712 * @details Initializes a socket
1713 * @param[out] sock The socket to initialize
1714 * @param[in] buffer The buffer to whom the socket belongs
1715 * @param[in] type Type of the socket
1716 * @param[in] data Socket config data
1717 * @return 0 on success, else -errno
1719 int socket_initialize(struct sock_data *sock, struct log_buffer *buffer, service_socket_t service_socket, struct socket_config_data *data)
1722 int sock_fd = listen_fd_create(data->path, data->permissions);
1726 init_fd_entity(&sock->fd_entity, dispatch_event_sock, sock);
1727 sock->service_socket = service_socket;
1728 sock->buf_ptr = buffer;
1729 set_read_fd_entity(&sock->fd_entity, sock_fd);
1735 * @brief Add writer to server
1736 * @details Adds a writer to the server's witers list and registers its event to epoll loop
1737 * @param[in] l The server to add the writer to
1738 * @param[in] writer The writer to add to the server and register its working_fd to epoll loop
1740 static void logger_add_writer(struct logger* l, struct writer* wr)
1745 list_add(&l->writers, wr);
1746 add_fd_entity(l, &wr->fd_entity);
1750 * @brief Create the logger server
1751 * @details Allocate the logger server's auxiliary structures (buffers etc.)
1752 * @param[in] data Initialisation data
1753 * @param[out] l The logger server
1754 * @return 0 on success, -errno on failure
1756 static int logger_create(struct logger_config_data *data, struct logger *l)
1758 memset(l, 0, sizeof *l);
1760 l->epollfd = epoll_create1(0);
1761 if (l->epollfd == -1)
1764 l->buf_params = data->buf_params;
1766 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
1767 if (data->is_buffer_enabled[id]) {
1768 int r = buffer_create(&l->buffers[id], id, data->buffers + id);
1773 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
1774 if (l->buffers[id]) {
1775 add_fd_entity(l, &l->buffers[id]->sock_ctl.fd_entity);
1776 add_fd_entity(l, &l->buffers[id]->sock_wr.fd_entity);
1779 /* TODO: make writers creation optional/configurable */
1780 int (*writers_factories[LOG_ID_MAX])(struct writer **writer, struct log_buffer *log_buf) = {
1781 [LOG_ID_KMSG] = create_kmsg_writer,
1782 [LOG_ID_SYSLOG] = create_syslog_writer,
1784 for (unsigned u = 0; u < NELEMS(writers_factories); ++u)
1785 if (writers_factories[u] && data->is_buffer_enabled[u]) {
1787 int r = writers_factories[u](&wr, l->buffers[u]);
1791 logger_add_writer(l, wr);
1797 static bool cond_writer_free(void *ptr, void *user_data)
1799 writer_free((struct writer *)ptr, user_data);
1804 * @brief Free logger
1805 * @details Deallocate the logger and its auxiliary structures
1806 * @param[in] l The logger server
1808 static void logger_free(struct logger *l)
1812 list_remove_if(&l->writers, l, cond_writer_free);
1813 list_remove_if(&l->extra_readers, l, cond_reader_free);
1816 for (j = 0; j < LOG_ID_MAX; j++)
1818 buffer_free(l->buffers[j], l);
1820 if (l->epollfd >= 0)
1825 * @brief Dispatch writer event
1826 * @details Receives and handles an event
1827 * @param[in] server The logger server
1828 * @param[in] event The received event
1830 void dispatch_event_writer(struct logger *server, struct epoll_event *event)
1834 struct writer *writer = (struct writer*)event->data.ptr;
1836 assert(writer->service_writer);
1837 int r = writer->service_writer(server, writer, event);
1839 list_remove(&server->writers, writer);
1840 writer_free(writer, server);
1845 * @brief Dispatch socket event
1846 * @details Receives and handles an event
1847 * @param[in] server The logger server
1848 * @param[in] event The received event
1850 void dispatch_event_sock(struct logger *server, struct epoll_event *event)
1853 struct sock_data const * const sock = (struct sock_data const * const) event->data.ptr;
1856 int sock_pipe = accept4(sock->fd_entity.fd, NULL, NULL, SOCK_NONBLOCK);
1857 if (sock_pipe < 0) {
1858 check_if_fd_limit_reached(server, errno);
1862 struct writer *writer;
1863 if (writer_create(&writer, sock_pipe, sock->buf_ptr, service_writer_socket, sock->service_socket) == 0)
1864 logger_add_writer(server, writer);
1870 * @brief Handle interrupting/terminating signals
1871 * @details Clears global flag to stop main loop
1872 * @param[in] signo signal number
1874 static void handle_signals(int signo)
1880 static void ensure_epoll_size(struct epoll_event **events, unsigned *size, unsigned wanted_size)
1885 if (wanted_size <= *size)
1888 typeof(*events) temp = realloc(*events, wanted_size * sizeof **events);
1893 *size = wanted_size;
1896 static int initialize_epoll_size(struct epoll_event **events, unsigned *size)
1901 static const size_t default_size = 16U;
1902 typeof(*events) ev = malloc(default_size * sizeof *ev);
1907 *size = default_size;
1913 * @details The main logging loop
1914 * @param[in] server The logger server
1915 * @return 0 on success, else -errno
1917 static int do_logger(struct logger* server)
1919 struct sigaction action = {
1920 .sa_handler = handle_signals,
1923 sigemptyset(&action.sa_mask);
1925 static const int handled_signals[] = { SIGINT, SIGTERM };
1926 for (unsigned u = 0; u < NELEMS(handled_signals); ++u)
1927 sigaction(handled_signals[u], &action, NULL);
1929 unsigned events_size;
1930 struct epoll_event *events;
1931 int r = initialize_epoll_size(&events, &events_size);
1934 while (g_logger_run) {
1935 clock_gettime(CLOCK_MONOTONIC, &server->now);
1937 ensure_epoll_size(&events, &events_size, server->epollcnt);
1939 int nfds = epoll_wait(server->epollfd, events, events_size, 1000);
1940 if (nfds < 0 && errno == EINTR) // TODO: This is *almost* TEMP_FAILURE_RETRY. Is it equivalent?
1948 for (int i = 0; i < nfds; i++) {
1949 struct fd_entity* entity = (struct fd_entity*) events[i].data.ptr;
1950 assert(entity->dispatch_event);
1951 entity->dispatch_event(server, &events[i]);
1953 service_all_readers(server);
1958 /* ensure all logs are written no matter when the program was interrupted */
1959 server->exiting = 1;
1960 service_all_readers(server);
1966 * @brief Prepare socket data
1967 * @details Extracts initialisation data specific to each socket
1968 * @param[in] conf Config database
1969 * @param[out] data Socket init config data
1970 * @param[in] buf_name The name of the buffer the socket belongs to
1971 * @param[in] type The name of the buffer type
1972 * @return 0 on success, -errno on failure
1974 int prepare_socket_data(const struct log_config *conf, struct socket_config_data *data, char *buf_name, const char *type)
1976 char conf_key[MAX_CONF_KEY_LEN];
1979 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock", buf_name, type);
1982 const char * const path = log_config_get(conf, conf_key);
1984 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock_rights", buf_name, type);
1987 const char * const permissions_str = log_config_get(conf, conf_key);
1989 if (!permissions_str || !path)
1992 data->permissions = parse_permissions(permissions_str);
1993 if (data->permissions <= 0)
1996 strncpy(data->path, path, MAX_CONF_VAL_LEN - 1);
2002 * @brief Prepare buffer data
2003 * @details Extracts data specific for each buffer
2004 * @param[in] conf Config database
2005 * @param[out] data Buffer init config data
2006 * @param[in] buf_id Index of the buffer to work with
2007 * @return 0 on success, -errno on failure
2009 int prepare_buffer_data(const struct log_config *conf, struct buffer_config_data *data, log_id_t buf_id)
2011 char * const buf_name = log_name_by_id(buf_id);
2012 char * validity_check_ptr;
2013 char conf_key[MAX_CONF_KEY_LEN];
2016 r = prepare_socket_data(conf, &data->write_socket, buf_name, "write");
2020 r = prepare_socket_data(conf, &data->ctl_socket, buf_name, "ctl");
2024 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_size", buf_name);
2028 const char * const size_str = log_config_get(conf, conf_key);
2032 data->size = strtol(size_str, &validity_check_ptr, 10);
2033 if (*validity_check_ptr)
2035 if (data->size <= 0)
2042 * @brief Save logfile line
2043 * @detail Saves logfile config line in user_data list
2044 * @param[in] key Config entry key
2045 * @param[in] value Config entry value
2046 * @param[in] userdata Userdata
2048 void save_logfile_config(char const *key, char const *value, void *userdata)
2051 if (strncmp(key, CONF_PREFIX, sizeof CONF_PREFIX - 1))
2054 struct logger_config_data *data = (struct logger_config_data *)userdata;
2055 void *cmd = (void *)strdup(value);
2057 list_add(&data->logfile_configs, cmd);
2062 * @brief Initialize config data
2063 * @param[out] The data structure to fill with initial values
2065 void initialize_config_data(struct logger_config_data *data)
2067 memset(data, 0, sizeof *data);
2071 * @brief Prepare config data
2072 * @details Extracts relevant config data for logger initialisation
2073 * @param[out] data Parsed configuration
2074 * @return 0 on success, -errno on failure
2076 int prepare_config_data(struct logger_config_data *data)
2080 struct log_config conf;
2081 int ret = log_config_read(&conf);
2085 const dlogutil_sorting_order_e sort_by = get_order_from_config(&conf);
2087 const char * const backend = log_config_get(&conf, "backend");
2092 int throttling_default = log_config_get_int(&conf, "logger_dev_throttling", LOGGER_DEVICE_THROTTLING_DEFAULT);
2094 for (int i = 0; i < LOG_ID_MAX; i++) {
2095 char key[MAX_CONF_KEY_LEN];
2096 const int r = snprintf(key, sizeof key, "logger_dev_throttling_%s", log_name_by_id((log_id_t)i));
2100 g_backend.logger_device_throttling[i] = max_int(1, log_config_get_int(&conf, key, throttling_default));
2103 memset(data->is_buffer_enabled, 0, sizeof(data->is_buffer_enabled));
2104 if (!strcmp(backend, "pipe")) {
2105 data->is_buffer_enabled[LOG_ID_MAIN] =
2106 data->is_buffer_enabled[LOG_ID_RADIO] =
2107 data->is_buffer_enabled[LOG_ID_SYSTEM] =
2108 data->is_buffer_enabled[LOG_ID_APPS] = 1;
2109 g_backend.reader_init = reader_init_for_pipe;
2110 } else if (!strcmp(backend, "logger")) {
2111 g_backend.reader_init = reader_init_for_logger;
2112 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
2113 const char *const logger_device = log_config_get(&conf, log_name_by_id(buf_id));
2115 strncpy(g_backend.logger_devices[buf_id], logger_device,
2116 NELEMS(g_backend.logger_devices[buf_id]) - 1);
2122 data->is_buffer_enabled[LOG_ID_KMSG] = log_config_get_boolean(&conf, "handle_kmsg", true);
2123 data->is_buffer_enabled[LOG_ID_SYSLOG] =
2124 dev_log_sock_get() >= 0 || log_config_get_boolean(&conf, "syslog_force", false);
2126 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
2127 if (data->is_buffer_enabled[buf_id]) {
2128 ret = prepare_buffer_data(&conf, data->buffers + buf_id, buf_id);
2131 data->buffers[buf_id].sort_by = sort_by;
2134 data->logfile_configs = NULL;
2135 log_config_foreach(&conf, save_logfile_config, data);
2138 log_config_free(&conf);
2142 static bool cond_string_free(void *ptr, void *user_data)
2149 static void free_config_data(struct logger_config_data *data)
2151 list_remove_if(&data->logfile_configs, NULL, cond_string_free);
2155 * @brief Parse logfile line
2156 * @detail Parses a logfile config line
2157 * @param[in] key Config entry key
2158 * @param[in] value Config entry value
2159 * @param[in] userdata Userdata
2161 void parse_logfile_config(void *value, void *userdata)
2166 struct logger *server = (struct logger *) userdata;
2167 struct reader *rd = NULL;
2168 char *configline = (char *) value;
2170 int r = parse_command_line(configline, NULL, server, &rd);
2172 add_reader(server, rd);
2175 printf("Warning: unable to add logutil reader for provided configuration. Ignoring.\n"
2176 " Config line: %s\n"
2177 " Reason given: %m\n",
2185 * @details Prints basic usage tips
2189 printf("Usage: %s [options]\n"
2190 "\t-h Show this help\n"
2191 "\t-b N Set the size of the log buffer (in bytes)\n"
2192 "\t-t N Set time between writes to file (in seconds)\n",
2193 program_invocation_short_name);
2198 * @details Parses execution parameters of the program
2199 * @param[in] argc Argument count
2200 * @param[in] argv Argument values
2201 * @param[out] b Buffering parameters
2202 * @return 0 or 1 on success, else -errno. Nonzero if the program is to close.
2204 static int parse_args(int argc, char **argv, struct buf_params *b)
2208 b->time = BUF_PARAM_TIME_DEFAULT;
2209 b->bytes = BUF_PARAM_BYTES_DEFAULT;
2211 while ((option = getopt(argc, argv, "hb:t:")) != -1) {
2214 if (!isdigit(optarg[0]))
2216 b->time = clamp_int(atoi(optarg), BUF_PARAM_TIME_MIN, BUF_PARAM_TIME_MAX);
2219 if (!isdigit(optarg[0]))
2221 b->bytes = clamp_int(atoi(optarg), BUF_PARAM_BYTES_MIN, BUF_PARAM_BYTES_MAX);
2236 * @brief Finalize initialisation
2237 * @details Do misc stuff needed at the end of the initialisation
2238 * @param[in] data configuration dat to read logfiles config lines from
2239 * @param[in] server logger instance to configure
2240 * @return 0 on success, -errno on failure
2242 static int finalize_init(struct logger_config_data *data, struct logger *server)
2244 int r = sd_notify(0, "READY=1");
2248 //create files after resetting self privileges
2249 list_foreach(data->logfile_configs, server, parse_logfile_config);
2256 * @return 0 on success, nonzero on failure
2257 * @retval 1 Configuration error
2258 * @retval 2 Runtime error
2260 int main(int argc, char** argv)
2264 signal(SIGPIPE, SIG_IGN);
2266 r = reset_self_privileges();
2269 printf("Unable to drop privileges to build-time defaults (%m). Exiting.\n");
2270 return DLOG_EXIT_ERR_RUNTIME;
2273 struct logger_config_data data;
2274 initialize_config_data(&data);
2276 if ((r = parse_args(argc, argv, &data.buf_params)) != 0) {
2280 return DLOG_EXIT_SUCCESS; // --help option
2283 printf("Unable to parse command line args (%m). Exiting.\n");
2284 return DLOG_EXIT_ERR_CONFIG;
2287 if ((r = prepare_config_data(&data)) != 0) {
2289 printf("Unable to prepare config (%m). Exiting.\n");
2290 return DLOG_EXIT_ERR_CONFIG;
2293 struct logger server;
2294 if ((r = logger_create(&data, &server)) < 0) {
2296 printf("Unable to initialize logger with provided configuration (%m). Exiting.\n");
2297 ret = DLOG_EXIT_ERR_CONFIG;
2301 if ((r = finalize_init(&data, &server)) < 0) {
2303 printf("Unable to finalize initialisation (%m). Exiting.\n");
2304 ret = DLOG_EXIT_ERR_CONFIG;
2308 if ((r = do_logger(&server)) < 0) {
2310 printf("Runtime failure (%m). Exiting.\n");
2311 ret = DLOG_EXIT_ERR_RUNTIME;
2315 ret = DLOG_EXIT_SUCCESS;
2318 free_config_data(&data);
2319 logger_free(&server);