#define BtoKiB(x) ((x) >> 10)
+struct log_file;
+typedef int (*logfile_hook_fn)(struct log_file *l_file);
+
struct log_file {
char *path;
int fd;
+ int should_close;
int size;
int rotate_size_kbytes;
int max_rotated;
+ logfile_hook_fn open_fn;
log_format *format;
};
-void open_logfile(struct log_file *file);
-void rotate_logs(struct log_file *file);
-int write_with_rotation(struct logger_entry *e, struct log_file *file);
+int logfile_init(struct log_file *l_file);
+void logfile_free(struct log_file *l_file);
+void logfile_set_fd(struct log_file *l_file, int fd, int should_close);
+int logfile_set_path(struct log_file *l_file, const char *path);
+int logfile_open(struct log_file *l_file, logfile_hook_fn open_fn);
+int logfile_rotate_needed(struct log_file *l_file);
+void logfile_do_rotate(struct log_file *file);
+int logfile_write_with_rotation(struct logger_entry *e, struct log_file *file);
#endif /* _LOG_FILE_H */
* @details Adds the header to a binary file
* @param[in] fd The file FD
* @return 0 on success, -errno on failure
+ * @remarks Called internally by logfile_open_internal()
*/
-static int add_misc_file_info(int fd)
+static int pipe_header_fn(struct log_file *l_file)
{
+ assert(l_file);
+ assert(l_file->fd >= 0);
+
+ if (l_file->size != 0)
+ return 0;
+
struct dlog_pipe_header header = {
.endian = PIPE_FILE_ENDIAN_MAGIC,
.version = PIPE_FILE_FORMAT_VERSION
};
- return (write(fd, &header, sizeof(header)) != sizeof(header)) ? -errno : 0;
+ return (write(l_file->fd, &header, sizeof(header)) != sizeof(header)) ? -errno : 0;
}
/**
reader->bytes_to_read -= ple->len;
if (plaintext) {
- write_with_rotation(ple, &reader->file);
+ logfile_write_with_rotation(ple, &reader->file);
continue;
}
reader->partial_log_size = ple->len - r;
memcpy(reader->partial_log, ple + r, reader->partial_log_size);
goto cleanup;
- } else if ((reader->file.rotate_size_kbytes > 0) &&
- (BtoKiB(reader->file.size) >= reader->file.rotate_size_kbytes)) {
+ } else if (logfile_rotate_needed(&reader->file) > 0) {
if (write_blob_to_file(reader, &g_file_buffer) < 0)
goto cleanup;
- rotate_logs(&reader->file);
- r = add_misc_file_info(reader->file.fd);
- if (r < 0) {
- ret = 1;
- goto cleanup;
- }
+ logfile_do_rotate(&reader->file);
}
}
*/
static void reader_free(struct reader* reader)
{
- if (reader->file.path)
- free(reader->file.path);
if (reader->fd_entity.fd >= 0)
close(reader->fd_entity.fd);
- if (reader->file.fd >= 0)
- close(reader->file.fd);
if (reader->read_fd >= 0)
close(reader->read_fd);
- log_format_free(reader->file.format);
+ logfile_free(&reader->file);
free(reader);
}
parse_androidlogger_message((struct android_logger_entry *) buffer, entry, r);
add_recv_timestamp(entry);
- write_with_rotation((struct logger_entry *) buffer, &reader->file);
+ logfile_write_with_rotation((struct logger_entry *)buffer, &reader->file);
}
}
char *tok;
char *tok_sv;
int retval = 0;
- struct reader * reader;
- struct stat stat_buf;
+ struct reader *reader;
int silence = 0;
if (!cmdl)
}
init_fd_entity(&reader->fd_entity, dispatch_event_reader, reader);
- reader->file.fd = -1;
- reader->file.path = NULL;
- reader->file.format = log_format_new();
- reader->file.rotate_size_kbytes = 0;
- reader->file.max_rotated = 0;
- reader->file.size = 0;
+
+ retval = logfile_init(&reader->file);
+ if (retval < 0)
+ goto cleanup;
+
reader->buf_id = LOG_ID_INVALID;
reader->read_fd = -1;
reader->dumpcount = 0;
}
if (reader->file.path != NULL) {
- int file_already_exists = !access(reader->file.path, F_OK);
- reader->file.fd = open(reader->file.path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
- if (reader->file.fd < 0) {
- retval = -errno;
- goto cleanup;
- }
-
const int plaintext = buf_writes_to_plaintext(reader->buf_id);
- if (!file_already_exists && !plaintext) {
- retval = add_misc_file_info(reader->file.fd);
- if (retval < 0)
- goto cleanup;
- }
-
- if (!fstat(reader->file.fd, &stat_buf)) {
- reader->file.size = stat_buf.st_size;
- if ((reader->file.rotate_size_kbytes > 0) &&
- (BtoKiB(reader->file.size) > reader->file.rotate_size_kbytes)) {
- rotate_logs(&(reader->file));
- if (!plaintext)
- add_misc_file_info(reader->file.fd);
- }
- }
+ retval = logfile_open(&reader->file, plaintext ? NULL : pipe_header_fn);
+ if (retval < 0)
+ goto cleanup;
} else {
- reader->file.rotate_size_kbytes = 0;
- reader->file.max_rotated = 0;
int fds[2];
if (pipe2(fds, O_CLOEXEC | O_NONBLOCK) < 0) {
retval = -errno;
}
}
-static inline void logfile_free(void *pointer)
-{
- struct log_file *l_file = pointer;
- if (l_file->format)
- log_format_free(l_file->format);
- if (l_file->fd != fileno(stdout))
- close(l_file->fd);
-}
-
static inline void sorting_vector_free(void *pointer)
{
struct sorting_vector *logs = pointer;
return -EPERM;
if ((logs->end + 1) % logs->size == logs->begin) {
- write_with_rotation(sort_vector_back(logs), l_file);
+ logfile_write_with_rotation(sort_vector_back(logs), l_file);
sort_vector_pop(logs);
}
}
if (ignore_timeout || timeout <= (s*1000 + ns/1000000)) {
- write_with_rotation(e, l_file);
+ logfile_write_with_rotation(e, l_file);
return 1;
} else
return 0;
if (push_log(temp, l_file, logs) < 0)
free(temp);
} else {
- int write_err = write_with_rotation(temp, l_file);
+ int write_err = logfile_write_with_rotation(temp, l_file);
free(temp);
if (!write_err && dump && !--dump) {
looping = 0;
return ret;
}
-int main(int argc, char ** argv)
+int main(int argc, char **argv)
{
char* buffer_names[SIMULTANEOUS_BUFFERS];
int buffer_cnt = 0;
int fdi_cnt = 0;
int i;
int tag_cnt = 0;
- struct stat stat_buf;
- __attribute__ ((cleanup(logfile_free))) struct log_file l_file = {
- .fd = fileno(stdout),
- .format = log_format_new(),
- };
+ __attribute__ ((cleanup(logfile_free))) struct log_file l_file;
__attribute__ ((cleanup(sorting_vector_free))) struct sorting_vector logs = {
.data = NULL,
.begin = 0,
.end = 0
};
+ int r;
- if (!l_file.format) {
- printf("Error: could not allocate memory!\n");
- return 1;
- }
+ r = logfile_init(&l_file);
+ if (r < 0)
+ goto err_nomem;
+ logfile_set_fd(&l_file, fileno(stdout), 0);
if (log_config_read(&conf) < 0) {
printf("Error: config could not be read!\n");
logs.size = atoi_check_numeric(optarg, &err_arg_nondigit);
break;
case 'f':
- l_file.path = optarg;
+ r = logfile_set_path(&l_file, optarg);
+ if (r < 0)
+ goto err_nomem;
break;
case 'v':
log_set_print_format(l_file.format, log_format_from_string(optarg));
if (IS_VECTOR_SIZE_SORTABLE(logs.size)) {
logs.data = (struct logger_entry**)calloc(logs.size, sizeof(struct logger_entry*));
- if (!logs.data) {
- printf("Failed to allocate sort buffer\n");
- return 1;
- }
+ if (!logs.data)
+ goto err_nomem;
}
-
if (should_getsize)
return do_getsize(&conf, buffer_names, buffer_cnt);
return 1;
}
- if (l_file.path) {
- l_file.fd = open(l_file.path, O_CREAT | O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR);
- if (l_file.fd < 0) {
- printf("Failed to open %s", l_file.path);
- return 1;
- }
-
- if (!fstat(l_file.fd, &stat_buf)) {
- l_file.size = stat_buf.st_size;
- if ((l_file.rotate_size_kbytes > 0) &&
- (BtoKiB(l_file.size) > l_file.rotate_size_kbytes))
- rotate_logs(&l_file);
- }
- } else {
- if (l_file.rotate_size_kbytes > 0 || l_file.max_rotated > 0) {
- printf("-n and -r option should be used with -f option\n");
- return 1;
- }
+ r = l_file.path ? logfile_open(&l_file, NULL) : 0;
+ if (r < 0) {
+ printf("Error while creating output file: %s\n", strerror(-r));
+ return 1;
}
for (i = 0; i < buffer_cnt; ++i) {
handle_pipe(fdi_ptrs, fdi_cnt, dump, &logs, &l_file);
return 0;
+
+err_nomem:
+ printf("Unable to allocate memory\n");
+ return 1;
}
/**
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
+#include <assert.h>
+
+#define DEFAULT_LOGFILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
/**
* @addtogroup SHARED_FUNCTIONS
* @{
*/
+int logfile_init(struct log_file *l_file)
+{
+ assert(l_file);
+
+ memset(l_file, 0, sizeof(struct log_file));
+
+ l_file->fd = -1;
+ l_file->format = log_format_new();
+
+ return l_file->format != NULL ? 0 : -1;
+}
+
+static void logfile_set_should_close(struct log_file *l_file, int on_off)
+{
+ assert(l_file);
+ if (on_off)
+ assert(l_file->fd >= 0);
+
+ l_file->should_close = !!on_off;
+}
+
+void logfile_set_fd(struct log_file *l_file, int fd, int should_close)
+{
+ assert(l_file);
+
+ l_file->fd = fd;
+ logfile_set_should_close(l_file, should_close);
+}
+
+int logfile_set_path(struct log_file *l_file, const char *path)
+{
+ assert(l_file);
+
+ if (l_file->path)
+ free(l_file->path);
+ char *p = strdup(path);
+ if (!p)
+ return -errno;
+
+ l_file->path = p;
+ return 0;
+}
+
+static void logfile_close_if_needed(struct log_file *l_file)
+{
+ assert(l_file);
+
+ if (l_file->fd >= 0 && l_file->should_close) {
+ close(l_file->fd);
+ logfile_set_should_close(l_file, 0);
+ l_file->fd = -1;
+
+ }
+}
+
+void logfile_free(struct log_file *l_file)
+{
+ assert(l_file);
+
+ if (l_file->format)
+ log_format_free(l_file->format);
+ if (l_file->path)
+ free(l_file->path);
+ logfile_close_if_needed(l_file);
+}
+
+static int logfile_update_fsize(struct log_file *l_file)
+{
+ assert(l_file);
+ assert(l_file->fd >= 0);
+
+ struct stat st;
+
+ if (fstat(l_file->fd, &st) < 0)
+ return -errno;
+
+ l_file->size = st.st_size;
+ return 0;
+}
+
+static int logfile_open_internal(struct log_file *l_file)
+{
+ assert(l_file);
+ assert(l_file->path);
+
+ logfile_close_if_needed(l_file);
+
+ int fd = open(l_file->path, O_CREAT | O_WRONLY | O_APPEND, DEFAULT_LOGFILE_PERM);
+ if (fd < 0)
+ return -errno;
+
+ logfile_set_fd(l_file, fd, 1);
+
+ l_file->fd = fd;
+ logfile_set_should_close(l_file, 1);
+
+ logfile_update_fsize(l_file);
+
+ if (l_file->open_fn)
+ l_file->open_fn(l_file);
+
+ return 0;
+}
+
/**
* @brief Open a log file
* @details Open a log file into the passed structure.
- * @param[in] file The file structure to contain the opened file descriptor
+ * @param[in] l_file The file structure to contain the opened file descriptor
+ * @param[in] open_fn Function called when new file is opened
* @remarks Creates the file if it does not exist, else appends to it.
*/
-void open_logfile(struct log_file *file)
+int logfile_open(struct log_file *l_file, logfile_hook_fn open_fn)
{
- file->fd = open(file->path,
- O_WRONLY | O_APPEND | O_CREAT,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
-
- if (file->fd < 0) {
- _E("could not open log file %s (%d)",
- file->path, errno);
- exit(EXIT_FAILURE);
- }
+ assert(l_file);
+
+ l_file->open_fn = open_fn;
+
+ int r = logfile_open_internal(l_file);
+ if (r < 0)
+ return r;
+
+ r = logfile_rotate_needed(l_file);
+ if (r > 0)
+ logfile_do_rotate(l_file);
+
+ return r;
+}
+
+/**
+ * @brief Checks if log file should be rotated
+ * @param[in] l_file The file structure to contain the currently opened file
+ * @remarks Updates l_file->size with on-disk file size
+ * @returns 1 if rotate is needed, 0 if not, -errno on error
+ */
+int logfile_rotate_needed(struct log_file *l_file)
+{
+ assert(l_file);
+
+ if (l_file->path == NULL || l_file->rotate_size_kbytes <= 0 || l_file->max_rotated <= 0)
+ return 0;
+
+ logfile_update_fsize(l_file);
+ return BtoKiB(l_file->size) > l_file->rotate_size_kbytes;
}
/**
* @details Opens a new file and moves existing files further back
* @param[in] file The file structure to contain the currently opened file
*/
-void rotate_logs(struct log_file *file)
+void logfile_do_rotate(struct log_file *file)
{
+ assert(file);
+ assert(file->path);
+
int i;
char path0[PATH_MAX];
char path1[PATH_MAX];
- close(file->fd);
for (i = file->max_rotated ; i > 0 ; i--) {
snprintf(path1, PATH_MAX, "%s.%d", file->path, i);
if (i - 1 == 0)
if (rename(path0, path1) < 0 && errno != ENOENT)
_E("while rotating log file: %s", file->path);
}
+
/* open log file again */
- open_logfile(file);
- file->size = 0;
+ logfile_open_internal(file);
}
/**
* @param[in] file The file to write to
* @returns 0 if log was successfully written, else 1
*/
-int write_with_rotation(struct logger_entry* e, struct log_file* file)
+int logfile_write_with_rotation(struct logger_entry *e, struct log_file *file)
{
log_entry entry;
if (log_process_log_buffer(e, &entry) || !log_should_print_line(file->format, entry.tag, entry.priority))
if (written_bytes <= 0)
return 1;
file->size += written_bytes;
- if ((file->rotate_size_kbytes > 0) && (BtoKiB(file->size) >= file->rotate_size_kbytes))
- rotate_logs(file);
+
+ if (logfile_rotate_needed(file))
+ logfile_do_rotate(file);
return 0;
}