return 0;
}
+/**
+ * @brief FD limit handler
+ * @details Checks whether the FD limit was reached and leaves logs about it if so
+ * @param[in] server The logger server
+ * @param[in] err errno from the call that failed to create an FD
+ */
+static void check_if_fd_limit_reached(struct logger *server, int err)
+{
+ assert(server);
+
+ if (err != ENFILE && err != EMFILE)
+ return;
+
+ printf("ERROR: dlog_logger fd limit reached!\n");
+
+ /* pick one representative buffer to send the log to;
+ * no point spamming all the buffers, especially since
+ * default dlogutil invocations display 3 buffers so
+ * it would appear multiple times */
+ struct log_buffer *const buf = server->buffers[LOG_ID_MAIN];
+ if (!buf)
+ return;
+
+ struct logger_entry_with_msg entry;
+ create_pipe_message(&entry,
+ DLOG_FATAL, /* not really FATAL, but since we're at the FD limit
+ * there are thousands of logging programs so this one
+ * would likely get lost in the flood since developers
+ * tend to overuse ERROR (and FATAL is the one above) */
+ "DLOG",
+ "\x1b[31m DLOG DAEMON FD LIMIT REACHED \x1b[0m" // make it stand out
+ );
+ buffer_append(&entry.header, buf);
+}
+
static int reader_print_out_single_log(struct reader *reader, const struct logger_entry *logger_entry)
{
assert(reader);
return 0;
}
-static int create_fifo_fds(int fifo_id, int *write_fd, int *read_fd)
+static int create_fifo_fds(struct logger *server, int fifo_id, int *write_fd, int *read_fd)
{
assert(write_fd);
assert(read_fd);
*read_fd = open(fifo_path, O_RDONLY | O_NONBLOCK);
if (*read_fd < 0) {
+ check_if_fd_limit_reached(server, errno);
ret = -errno;
goto finish;
}
*write_fd = open(fifo_path, O_WRONLY | O_NONBLOCK);
if (*write_fd < 0) {
+ check_if_fd_limit_reached(server, errno);
ret = -errno;
close(*read_fd);
goto finish;
goto cleanup;
} else if (wr) {
int write_fd = -1, read_fd = -1;
- if (create_fifo_fds(wr->fd_entity.fd, &write_fd, &read_fd) < 0)
+ if (create_fifo_fds(server, wr->fd_entity.fd, &write_fd, &read_fd) < 0)
goto cleanup;
set_write_fd_entity(&reader->fd_entity, write_fd);
return -EINVAL;
int pipe_fd[2];
- 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
+ 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
+ check_if_fd_limit_reached(server, errno);
return -errno;
+ }
r = fcntl(pipe_fd[1], F_SETPIPE_SZ, PIPE_REQUESTED_SIZE);
if (r < 0)
assert(sock);
int sock_pipe = accept4(sock->fd_entity.fd, NULL, NULL, SOCK_NONBLOCK);
- if (sock_pipe < 0)
+ if (sock_pipe < 0) {
+ check_if_fd_limit_reached(server, errno);
return;
+ }
struct writer *writer;
if (writer_create(&writer, sock_pipe, sock->buf_ptr, service_writer_socket, sock->service_socket) == 0)