/**
* @brief Create struct fd_info
* @details Allocates memory for the struct and initializes it with given arguments
- * @param[in] fd file descriptor
- * @param[in] do_sorting specifies if the logs read from fd should be sorted
- * @param[in] log_len up to how many bytes the logs should be read from fd
- * UNLIMITED_LOG_LEN for unlimited logs reading
- * @param[in] type source type we read from defined in enum fd_type
+ * @param[in] ops source-dependent operation set
* @return FD created struct or NULL on memory allocation failure
*/
-struct fd_info *fdi_create(int fd, int do_sorting, int log_len, fd_type type)
+struct fd_info *fdi_create(struct fd_ops *ops, const char *name)
{
+ assert(ops);
+
struct fd_info *fdi = malloc(sizeof(struct fd_info));
if (!fdi)
return NULL;
- fdi->fd = fd;
- fdi->do_sorting = do_sorting;
- fdi->log_len = log_len;
- fdi->type = type;
- fdi->index = 0;
+ fdi->fd = -1;
+ fdi->log_len = UNLIMITED_LOG_LEN;
+ fdi->ops = ops;
+ fdi->name = name;
+ fdi->priv_data = NULL;
return fdi;
}
if (!fdi)
return;
+ if (fdi->ops->destroy)
+ fdi->ops->destroy(fdi);
+
if (fdi->fd >= 0)
close(fdi->fd);
+
free(fdi);
}
free(*arr);
}
-bool fdi_has_log(struct fd_info *fdi)
+bool generic_has_log(struct fd_info *fdi)
{
assert(fdi);
- const struct logger_entry *const le = (const struct logger_entry *)fdi->buff;
- return fdi->index >= sizeof le->len && fdi->index >= le->len;
+ struct generic_priv_data *gpd = (struct generic_priv_data *)fdi->priv_data;
+ assert(gpd);
+
+ const struct logger_entry *const le = (const struct logger_entry *)gpd->buff;
+ return gpd->index >= sizeof le->len && gpd->index >= le->len;
}
-int fdi_push_log(struct fd_info *fdi, int *dump, struct sort_vector *logs, struct log_file *l_file)
+int fdi_push_log(struct fd_info *fdi, struct sort_vector *logs, struct log_file *l_file)
{
assert(fdi);
- assert(dump);
assert(l_file);
- struct logger_entry *temp = fdi_extract_entry(fdi);
+ struct logger_entry *temp = fdi->ops->extract_entry(fdi);
if (!temp)
return -ENOMEM;
- if (fdi->do_sorting) {
- sort_vector_push(logs, temp, l_file);
- } else {
- int write_err = logfile_write_with_rotation(temp, l_file);
- free(temp);
- if (!write_err && *dump && !--*dump)
- return 1;
- }
+ sort_vector_push(logs, temp, l_file);
return 0;
}
-struct logger_entry *fdi_extract_entry(struct fd_info *fdi)
+struct logger_entry *generic_extract_entry(struct fd_info *fdi)
{
assert(fdi);
+ struct generic_priv_data *gpd = (struct generic_priv_data *)fdi->priv_data;
+ assert(gpd);
- struct logger_entry *const buf_le = (struct logger_entry *)fdi->buff;
+ struct logger_entry *const buf_le = (struct logger_entry *)gpd->buff;
if (!buf_le->len)
return NULL;
return NULL;
memcpy(new_le, buf_le, buf_le->len);
- fdi->index -= buf_le->len;
- memmove(fdi->buff, fdi->buff + buf_le->len, fdi->index);
+ gpd->index -= buf_le->len;
+ memmove(gpd->buff, gpd->buff + buf_le->len, gpd->index);
return new_le;
}
-int fdi_read(struct fd_info *fdi)
+int generic_read(struct fd_info *fdi)
{
assert(fdi);
+ struct generic_priv_data *gpd = (struct generic_priv_data *)fdi->priv_data;
+ assert(gpd);
- if (fdi->index == RECEIVE_BUFFER_SIZE)
+ if (gpd->index == RECEIVE_BUFFER_SIZE)
return -EAGAIN;
- int r = read(fdi->fd, fdi->buff + fdi->index, RECEIVE_BUFFER_SIZE - fdi->index);
+ int r = read(fdi->fd, gpd->buff + gpd->index, RECEIVE_BUFFER_SIZE - gpd->index);
if (r < 0)
return -errno;
- if (fdi->type == ANDROID_LOGGER) {
- struct logger_entry *const le = (struct logger_entry *)fdi->buff;
- parse_androidlogger_message((struct android_logger_entry *)fdi->buff, le, r);
- add_recv_timestamp(le);
- fdi->index = le->len;
- } else {
- fdi->index += r;
- }
-
- if (fdi->log_len > 0)
- fdi->log_len -= r;
-
+ gpd->index += r;
return r;
}
#pragma once
#include <stdbool.h>
+#include <logconfig.h>
#include <log_file.h>
+#include <logprint.h>
+#include <ptrs_list.h>
#include <queued_entry.h>
#include "sort_vector.h"
-#define RECEIVE_BUFFER_SIZE 16384 // How large (in bytes) the pipe receiving buffer is.
+#define RECEIVE_BUFFER_SIZE 16384 // How large (in bytes) pipe receiving buffer is.
#define UNLIMITED_LOG_LEN (-RECEIVE_BUFFER_SIZE - 1) // value not reachable through a single read()
-typedef enum {
- PIPE,
- BINARY_FILE,
- ANDROID_LOGGER
-} fd_type;
+struct fd_ops;
struct fd_info {
int fd;
- int do_sorting;
int log_len;
- fd_type type;
- int index;
- char buff[RECEIVE_BUFFER_SIZE];
+ struct fd_ops *ops;
+ const char *name;
+ void *priv_data;
+};
+
+
+struct fd_ops {
+ /// Lifetime management: constructor and destructor
+ int (*create)(struct fd_info *fdi, struct log_config *conf, const char *name);
+ void (*destroy)(struct fd_info *fdi);
+
+ /// Read an entry into an internal buffer; requires `prepare_print` to have been called
+ int (*read)(struct fd_info *fdi);
+
+ /// Checks whether a log has been buffered and is ready for extraction
+ bool (*has_log)(struct fd_info *fdi);
+
+ /// Extracts a buffered entry and relinquishes its ownership
+ struct logger_entry *(*extract_entry)(struct fd_info *fdi);
+
+ /// Transition into a state that allows reading and printing out logs
+ int (*prepare_print)(struct fd_info *fdi, int dump, list_head filters, log_format *format);
+
+ /// Clear the buffer
+ int (*clear)(struct fd_info *fdi);
};
-struct fd_info *fdi_create(int fd, int do_sorting, int log_len, fd_type type);
+struct fd_info *fdi_create(struct fd_ops *ops, const char *name);
void fdi_free(struct fd_info *fdi);
void fdi_array_free(struct fd_info ***arr);
bool fdi_has_log(struct fd_info *fdi);
-int fdi_push_log(struct fd_info *fdi, int *dump, struct sort_vector *logs, struct log_file *l_file);
+int fdi_push_log(struct fd_info *fdi, struct sort_vector *logs, struct log_file *l_file);
struct logger_entry *fdi_extract_entry(struct fd_info *fdi);
int fdi_read(struct fd_info *fdi);
+
+struct generic_priv_data {
+ size_t index;
+ char buff[RECEIVE_BUFFER_SIZE];
+};
+
+int generic_read(struct fd_info *fdi);
+struct logger_entry *generic_extract_entry(struct fd_info *fdi);
+bool generic_has_log(struct fd_info *fdi);
+
/**
* @brief Handle a file
- * @details Checks validity of a binary file
- * @param[in] filename The file name
- * @return A fd wrapper struct on valid file, else NULL
+ * @details Opens and checks validity of a binary file
+ * @param[in] fdi The fd info to work with
+ * @param[in] conf The configuration to use
+ * @return 0 on success, -errno on failure
*/
-struct fd_info *handle_file(char const *filename)
+static int binaryfile_create(struct fd_info *fdi, struct log_config *conf, const char *name)
{
- assert(filename);
+ assert(fdi);
+ assert(conf);
+ assert(name);
- int r;
- int fd;
-
- fd = open(filename, O_RDONLY);
+ int fd = open(name, O_RDONLY);
if (fd < 0) {
- fprintf(stderr, "File \"%s\" could not be opened: %m\n", filename);
- return NULL;
+ fprintf(stderr, "File \"%s\" could not be opened: %m\n", name);
+ return -errno;
}
struct dlog_pipe_header header;
- r = read(fd, &header, sizeof header);
+ int r = read(fd, &header, sizeof header);
if (r < 0) {
- fprintf(stderr, "File \"%s\" read failed! %m\n", filename);
+ r = -errno;
+ fprintf(stderr, "File \"%s\" read failed! %m\n", name);
goto closefile;
} else if (r < sizeof header) {
- fprintf(stderr, "File \"%s\" does not contain a full header!\n", filename);
+ fprintf(stderr, "File \"%s\" does not contain a full header!\n", name);
+ r = -EINVAL;
goto closefile;
}
if (header.endian != PIPE_FILE_ENDIAN_MAGIC) {
- fprintf(stderr, "File \"%s\": unsupported endianness!\n", filename);
+ fprintf(stderr, "File \"%s\": unsupported endianness!\n", name);
+ r = -EINVAL;
goto closefile;
}
if (header.version != PIPE_FILE_FORMAT_VERSION) {
- fprintf(stderr, "File \"%s\": file format version is %d but only %d is supported!\n", filename, header.version, PIPE_FILE_FORMAT_VERSION);
+ fprintf(stderr, "File \"%s\": file format version is %d but only %d is supported!\n", name, header.version, PIPE_FILE_FORMAT_VERSION);
+ r = -EINVAL;
goto closefile;
}
- struct fd_info *fdi = fdi_create(fd, 1, UNLIMITED_LOG_LEN, BINARY_FILE);
- if (!fdi) {
- fprintf(stderr, "Error: not enough memory\n");
+ struct generic_priv_data *gpd = malloc(sizeof(struct generic_priv_data));
+ if (!gpd) {
+ fprintf(stderr, "Error not enough memory\n");
+ r = -ENOMEM;
goto closefile;
}
- return fdi;
+ gpd->index = 0;
+ fdi->priv_data = gpd;
+
+ fdi->fd = fd;
+ return 0;
closefile:
close(fd);
- return NULL;
+ return r;
+}
+
+static void binaryfile_destroy(struct fd_info *fdi)
+{
+ assert(fdi);
+
+ if (!fdi->priv_data)
+ return;
+
+ free(fdi->priv_data);
+ fdi->priv_data = NULL;
}
+static int binaryfile_prepare_print(struct fd_info *fdi, int dump, list_head filters, log_format *format)
+{
+ assert(fdi);
+ assert(filters);
+ assert(format);
+
+ for (list_head iter = filters; iter; list_next(&iter))
+ log_add_filter_string(format, (const char *)list_at(iter));
+
+ return 0;
+}
+
+struct fd_ops ops_binfile = {
+ .create = binaryfile_create,
+ .destroy = binaryfile_destroy,
+ .read = generic_read,
+ .has_log = generic_has_log,
+ .extract_entry = generic_extract_entry,
+ .prepare_print = binaryfile_prepare_print,
+};
+
#include "fd_info.h"
-struct fd_info *handle_file(char const *filename);
+extern struct fd_ops ops_binfile;
#include "fd_info.h"
#include "fdi_logger.h"
+struct logger_priv_data {
+ struct logger_entry *entry;
+};
+
/**
* @brief Get buffer filled size
* @details Sends a get log len ioctl to given fd
/**
* @brief Clear the buffer
* @details Sends a clear ioctl to given fd
- * @param[in] fd File descriptor of the buffer
- * @remarks ANDROID LOGGER version
+ * @param[in] fdi File descriptor info
+ * @return 0 on success, -errno on failure
*/
-static void clear_log_logger(int fd)
+static int logger_clear(struct fd_info *fdi)
{
- int ret = ioctl(fd, LOGGER_FLUSH_LOG);
- if (ret < 0)
+ assert(fdi);
+ assert(fdi->fd >= 0);
+
+ int ret = ioctl(fdi->fd, LOGGER_FLUSH_LOG);
+ if (ret < 0) {
_E("ioctl LOGGER_FLUSH_LOG failed (%d)", errno);
+ return -errno;
+ }
+
+ return 0;
}
/**
- * @brief Process buffer (non-pipe version)
- * @details Finalizes a buffer: sends the appropriate socket request
- * @param[in] buffer_name The name of the buffer
- * @param[in] clear Whether to clear the buffer
+ * @brief Open an Android Logger device
+ * @param[in] fdi File descriptor info
* @param[in] conf The configuration
- * @param[in] dump Whether dumping or not
- * @param[in] filters List of filters
- * @param[in] format Log processing format
- * @return FD wrapper structure to read from
+ * @return 0 on success, -errno on failure
*/
-struct fd_info *process_buffer_nonpipe(const char *buffer_name, int clear, struct log_config *conf, list_head filters, log_format *format)
+static int logger_create(struct fd_info *fdi, struct log_config *conf, const char *name)
{
- for (list_head iter = filters; iter; list_next(&iter))
- log_add_filter_string(format, (const char *)list_at(iter));
+ assert(fdi);
+ assert(conf);
+ assert(name);
char const *dev_path;
- dev_path = log_config_get(conf, buffer_name);
+ dev_path = log_config_get(conf, name);
if (!dev_path)
- return NULL;
+ return -ENOENT;
- int fd = open(dev_path, clear ? O_WRONLY : O_RDONLY);
- if (fd < 0)
- return NULL;
+ struct logger_priv_data *lpd = malloc(sizeof *lpd);
+ if (!lpd)
+ return -ENOMEM;
+ lpd->entry = NULL;
- if (clear) {
- clear_log_logger(fd);
- goto cleanup;
+ int fd = open(dev_path, O_RDWR);
+ if (fd < 0) {
+ free(lpd);
+ return -errno;
}
- const int log_len = logger_get_log_len(fd);
+ fdi->priv_data = lpd;
+ fdi->fd = fd;
+ return 0;
+}
+
+static void logger_destroy(struct fd_info *fdi)
+{
+ assert(fdi);
+ struct logger_priv_data *lpd = (struct logger_priv_data *)fdi->priv_data;
+
+ if (!lpd)
+ return;
+
+ free(lpd->entry);
+ free(lpd);
+ fdi->priv_data = NULL;
+}
+
+static int logger_prepare_print(struct fd_info *fdi, int dump, list_head filters, log_format *format)
+{
+ assert(fdi);
+ assert(format);
+
+ for (list_head iter = filters; iter; list_next(&iter))
+ log_add_filter_string(format, (const char *)list_at(iter));
+
+ if (!dump)
+ return 0;
+
+ const int log_len = logger_get_log_len(fdi->fd);
if (log_len < 0)
- goto cleanup;
+ return log_len;
+
+ fdi->log_len = log_len;
+ return 0;
+}
+
+static int logger_read(struct fd_info *fdi)
+{
+ assert(fdi);
+ struct logger_priv_data *lpd = (struct logger_priv_data *)fdi->priv_data;
+ assert(lpd);
+ assert(!lpd->entry);
+
+ char buff[LOG_MAX_SIZE];
+ int r = read(fdi->fd, buff, sizeof buff);
+ if (r < 0)
+ return -errno;
+
+ struct android_logger_entry *const ale = (struct android_logger_entry *)buff;
+ if (r <= sizeof *ale)
+ return -EINVAL;
- struct fd_info *fdi = fdi_create(fd, 1, log_len, ANDROID_LOGGER);
- if (!fdi)
- goto cleanup;
+ lpd->entry = malloc(r - sizeof *ale + sizeof *lpd->entry);
+ if (!lpd->entry)
+ return -ENOMEM;
- return fdi;
+ parse_androidlogger_message(ale, lpd->entry, r);
+ add_recv_timestamp(lpd->entry);
-cleanup:
- close(fd);
- return NULL;
+ if (fdi->log_len > 0)
+ fdi->log_len -= r;
+
+ return r;
}
+static struct logger_entry *logger_extract_entry(struct fd_info *fdi)
+{
+ assert(fdi);
+ struct logger_priv_data *lpd = (struct logger_priv_data *)fdi->priv_data;
+ assert(lpd);
+
+ struct logger_entry *const ret = lpd->entry;
+ lpd->entry = NULL;
+ return ret;
+}
+
+static bool logger_has_log(struct fd_info *fdi)
+{
+ assert(fdi);
+ struct logger_priv_data *lpd = (struct logger_priv_data *)fdi->priv_data;
+ assert(lpd);
+
+ return lpd->entry != NULL;
+}
+
+struct fd_ops ops_logger = {
+ .create = logger_create,
+ .destroy = logger_destroy,
+ .read = logger_read,
+ .has_log = logger_has_log,
+ .extract_entry = logger_extract_entry,
+ .prepare_print = logger_prepare_print,
+ .clear = logger_clear,
+};
+
#pragma once
-#include <logconfig.h>
-#include <logprint.h>
-#include <ptrs_list.h>
#include "fd_info.h"
-struct fd_info *process_buffer_nonpipe(const char *buffer_name, int clear, struct log_config *conf, list_head filters, log_format *format);
+extern struct fd_ops ops_logger;
#include "fd_info.h"
#include "fdi_pipe.h"
+struct pipe_priv_data {
+ struct generic_priv_data gpd; // "base class", has to be first
+ int sock_fd;
+};
+
/**
* @brief Clear request
* @details Send a CLEAR request to the logger daemon
- * @param[in] sock_fd The socket to send the request over
- * @return 1 on success, 0 on failure
+ * @param[in] fdi The fd info to work on
+ * @return 0 on success, -errno on failure
*/
-static int do_clear_pipe(int sock_fd)
+static int pipe_clear(struct fd_info *fdi)
{
- assert(sock_fd >= 0);
+ assert(fdi);
+ struct pipe_priv_data *ppd = (struct pipe_priv_data *)fdi->priv_data;
+ assert(ppd);
+ assert(ppd->sock_fd >= 0);
- int r = send_dlog_request(sock_fd, DLOG_REQ_CLEAR, NULL, 0);
+ int r = send_dlog_request(ppd->sock_fd, DLOG_REQ_CLEAR, NULL, 0);
if (r < 0)
printf("Error: could not send a CLEAR request to logger %s\n", strerror(-r));
return r;
}
+
/**
- * @brief Process buffer (pipe version)
- * @details Finalizes a buffer: sends the appropriate socket request
- * @param[in] buffer_name The name of the buffer
- * @param[in] clear Whether to clear the buffer
+ * @brief Open a connection to the dlog daemon
+ * @param[in] fdi File descriptor info
* @param[in] conf The configuration
- * @param[in] dump Whether dumping or not
- * @param[in] filters List of filters
- * @param[in] format Log processing format
- * @return FD wrapper structure of a pipe if we are to read from one, else NULL
+ * @return 0 on success, -errno on failure
*/
-
-struct fd_info *process_buffer_pipe(const char *buffer_name, int clear, struct log_config *conf, int dump, list_head filters, log_format *format)
+static int pipe_create(struct fd_info *fdi, struct log_config *conf, const char *name)
{
- char conf_key[MAX_CONF_KEY_LEN];
- char const * sock_path;
- int sock_fd = -1;
- int pipe_fd;
- struct fd_info *ret = NULL;
+ assert(fdi);
+ assert(conf);
+ assert(name);
- log_add_filter_string(format, "*:V"); // use the widest possible filter to let everything through as data are already filtered daemonside
+ char conf_key[MAX_CONF_KEY_LEN];
+ snprintf(conf_key, sizeof(conf_key), "%s_ctl_sock", name);
- snprintf(conf_key, sizeof(conf_key), "%s_ctl_sock", buffer_name);
- sock_path = log_config_get(conf, conf_key);
+ const char *sock_path = log_config_get(conf, conf_key);
if (!sock_path) {
- printf("Error: Socket %s is unavailable!\n", conf_key);
- goto cleanup;
+ printf("Error: no config entry for %s!\n", conf_key);
+ return -ENOENT;
}
- sock_fd = connect_sock(sock_path);
+ int sock_fd = connect_sock(sock_path);
if (sock_fd < 0) {
- printf("Error: Could not connect to socket %s!\n", sock_path);
- goto cleanup;
+ printf("Error: Could not connect to socket %s %s!\n", sock_path, strerror(-sock_fd));
+ return sock_fd;
}
- if (clear) {
- do_clear_pipe(sock_fd);
- goto cleanup;
+ struct pipe_priv_data *ppd = malloc(sizeof *ppd);
+ if (!ppd) {
+ printf("Error: not enough memory\n");
+ close(sock_fd);
+ return -ENOMEM;
}
+ ppd->gpd.index = 0;
+ ppd->sock_fd = sock_fd;
- if (send_logger_request(filters, dump, sock_fd) < 0) {
- printf("Error: could not send request to logger daemon\n");
- goto cleanup;
- }
+ fdi->priv_data = ppd;
+ return 0;
+}
- pipe_fd = recv_pipe(sock_fd);
- if (pipe_fd < 0) {
- printf("Error: couldn't retrieve pipe fd\n");
- goto cleanup;
- }
+static void pipe_destroy(struct fd_info *fdi)
+{
+ assert(fdi);
+ struct pipe_priv_data *ppd = (struct pipe_priv_data *)fdi->priv_data;
+ if (!ppd)
+ return;
- int do_sorting = strcmp(buffer_name, "kmsg") && strcmp(buffer_name, "syslog");
- ret = fdi_create(pipe_fd, do_sorting, UNLIMITED_LOG_LEN, PIPE);
+ if (ppd->sock_fd >= 0)
+ close(ppd->sock_fd);
+ free(ppd);
- if (!ret) {
- close(pipe_fd);
- goto cleanup;
- }
+ fdi->priv_data = NULL;
+}
-cleanup:
- if (sock_fd >= 0)
- close(sock_fd);
+static int pipe_prepare_print(struct fd_info *fdi, int dump, list_head filters, log_format *format)
+{
+ assert(filters);
+ assert(format);
+ assert(fdi);
+ struct pipe_priv_data *ppd = (struct pipe_priv_data *)fdi->priv_data;
+ assert(ppd);
+ assert(ppd->sock_fd >= 0);
- return ret;
+ log_add_filter_string(format, "*:V"); // lets everything through (actual filtering done by the daemon)
+
+ int r = send_logger_request(filters, dump, ppd->sock_fd);
+ if (r < 0)
+ return r;
+
+ int pipe_fd = recv_pipe(ppd->sock_fd);
+ if (pipe_fd < 0)
+ return pipe_fd;
+
+ fdi->fd = pipe_fd;
+
+ return 0;
}
+struct fd_ops ops_pipe = {
+ .create = pipe_create,
+ .destroy = pipe_destroy,
+ .read = generic_read,
+ .has_log = generic_has_log,
+ .extract_entry = generic_extract_entry,
+ .prepare_print = pipe_prepare_print,
+ .clear = pipe_clear,
+};
+
#pragma once
-#include <logconfig.h>
-#include <logprint.h>
-#include <ptrs_list.h>
#include "fd_info.h"
-struct fd_info *process_buffer_pipe(const char *buffer_name, int clear, struct log_config *conf, int dump, list_head filters, log_format *format);
+extern struct fd_ops ops_pipe;
* @param[in] logs The log sorting vector
* @param[in] l_file File output metadata
*/
-static void handle_pipe(struct fd_info **data_fds, int fd_count, int dump, struct sort_vector *logs, struct log_file *l_file)
+static void do_print(struct fd_info **data_fds, int fd_count, int dump, struct sort_vector *logs, struct log_file *l_file)
{
assert(data_fds);
assert(logs);
ev.data.ptr = data_fds[nfds];
if (fd_set_flags(fd, O_NONBLOCK) < 0)
return;
- if (data_fds[nfds]->type == PIPE)
+ if (data_fds[nfds]->ops == &ops_pipe) // HACK
++pipes;
- if (data_fds[nfds]->type != BINARY_FILE) {
+ if (data_fds[nfds]->ops != &ops_binfile) { // HACK
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
struct fd_info *swap_tmp = data_fds[nfds];
data_fds[nfds--] = data_fds[--fd_count];
continue;
}
- r = fdi_read(fdi);
+ r = fdi->ops->read(fdi);
if (r < 0) {
if (r == -EAGAIN)
continue;
}
if (r == 0 || (dump && fdi->log_len <= 0 && fdi->log_len != UNLIMITED_LOG_LEN)) {
- if (fdi->type != BINARY_FILE)
+ if (fdi->ops != &ops_binfile) // HACK
epoll_ctl(epollfd, EPOLL_CTL_DEL, fdi->fd, NULL);
- if (fdi->type == PIPE && dump)
+ if (fdi->ops == &ops_pipe && dump) // HACK
--pipes;
else if (--fd_count <= 0) {
accepting_logs = 0;
}
}
- while (fdi_has_log(fdi))
- if (fdi_push_log(fdi, &dump, logs, l_file)) {
+ while (fdi->ops->has_log(fdi))
+ if (fdi_push_log(fdi, logs, l_file)) {
looping = 0;
break;
}
return 1;
}
+int create_initial_fdis(struct fd_info ***fdis, int enabled_buffers, list_head file_input_names, struct fd_ops *buffer_op, struct log_config *conf)
+{
+ assert(fdis);
+ assert(buffer_op);
+ assert(conf);
+
+ struct fd_info **fdi_ptrs = calloc(list_count(file_input_names) + bit_count(enabled_buffers) + 1 /* NULL terminator */, sizeof *fdi_ptrs);
+ if (!fdi_ptrs)
+ return -ENOMEM;
+
+ int fdi_cnt = 0;
+ int ret = 0;
+ for (int i = 0; i < LOG_ID_MAX; ++i) {
+ if (!bit_test(enabled_buffers, i))
+ continue;
+
+ const char *const bufname = log_name_by_id(i);
+ struct fd_info *fdi;
+ switch (i) {
+ case LOG_ID_KMSG:
+ case LOG_ID_SYSLOG:
+ fdi = fdi_create(&ops_pipe, bufname);
+ break;
+ default:
+ fdi = fdi_create(buffer_op, bufname);
+ break;
+ }
+ if (!fdi) {
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ if (fdi->ops->create(fdi, conf, bufname) < 0) {
+ printf("Unable to access buffer \"%s\"\n", bufname);
+ fdi_free(fdi);
+ continue;
+ }
+ fdi_ptrs[fdi_cnt++] = fdi;
+ }
+ if (enabled_buffers && !fdi_cnt) {
+ ret = -EINVAL;
+ goto failure;
+ }
+
+ for (list_head iter = file_input_names; iter; list_next(&iter)) {
+ const char *const filename = (const char *)list_at(iter);
+ struct fd_info *fdi = fdi_create(&ops_binfile, filename);
+ if (!fdi) {
+ ret = -ENOMEM;
+ goto failure;
+ }
+ if (fdi->ops->create(fdi, conf, filename) < 0) {
+ printf("Unable to access file \"%s\"\n", filename);
+ fdi_free(fdi);
+ continue;
+ }
+ fdi_ptrs[fdi_cnt++] = fdi;
+ }
+
+ *fdis = fdi_ptrs;
+ return fdi_cnt;
+
+failure:
+
+ fdi_array_free(&fdi_ptrs);
+ return ret;
+}
+
int main(int argc, char **argv)
{
int enabled_buffers = 0; // bitset
return 1;
}
- fdi_ptrs = calloc(list_count(file_input_names) + bit_count(enabled_buffers) + 1 /* NULL terminator */, sizeof *fdi_ptrs);
- if (!fdi_ptrs) {
- printf("Error not enough memory\n");
+ fdi_cnt = create_initial_fdis(&fdi_ptrs, enabled_buffers, file_input_names, !strcmp(conf_value, "pipe") ? &ops_pipe : &ops_logger, &conf);
+ if (fdi_cnt < 0) {
+ printf("Error creating fd info: %s\n", strerror(-fdi_cnt));
return 1;
}
- for (i = 0; i < LOG_ID_MAX; ++i) {
- if (!bit_test(enabled_buffers, i))
- continue;
+ for (i = 0; i < fdi_cnt; ++i) {
+ struct fd_info *const fdi = fdi_ptrs[i];
- struct fd_info *fdi;
- const char *const bufname = log_name_by_id(i);
- if (!strcmp(conf_value, "pipe")
- || !strcmp(bufname, "syslog")
- || !strcmp(bufname, "kmsg"))
- fdi = process_buffer_pipe(bufname, action == ACTION_CLEAR, &conf, dump, filters, l_file.format);
- else
- fdi = process_buffer_nonpipe(bufname, action == ACTION_CLEAR, &conf, filters, l_file.format);
- if (fdi) {
- fdi_ptrs[fdi_cnt++] = fdi;
- if (bit_count(enabled_buffers) == 1 || !IS_VECTOR_SIZE_SORTABLE(logs.size))
- fdi->do_sorting = 0;
- } else {
- printf("Unable to access buffer \"%s\"\n", bufname);
+ int r = 0;
+ switch (action) {
+ case ACTION_CLEAR:
+ r = fdi->ops->clear(fdi);
+ break;
+ case ACTION_PRINT: {
+ r = fdi->ops->prepare_print(fdi, dump, filters, l_file.format);
+ break;
+ } case ACTION_GETSIZE:
+ // r = fdi->ops->getsize(fdi);
+ break;
+ default:
+ assert(false);
}
- }
- if (bit_count(enabled_buffers) > 0 && !fdi_cnt)
- return 1;
- if (action == ACTION_CLEAR)
- return 0;
-
- for (list_head iter = file_input_names; iter; list_next(&iter)) {
- struct fd_info *fdi = handle_file((const char *)list_at(iter));
- if (!fdi)
+ if (r < 0) {
+ static const char *action_names[] = {
+ [ACTION_PRINT] = "preparing for printing",
+ [ACTION_GETSIZE] = "size getting",
+ [ACTION_CLEAR] = "buffer clearing",
+ };
+ printf("Error while %s: %s\n", action_names[action], strerror(-r));
return 1;
- fdi_ptrs[fdi_cnt++] = fdi;
+ }
}
- handle_pipe(fdi_ptrs, fdi_cnt, dump, &logs, &l_file);
+ if (action == ACTION_PRINT)
+ do_print(fdi_ptrs, fdi_cnt, dump, &logs, &l_file);
return 0;