Unify logfile handling (including rotation) across util & server 16/143816/2
authorKarol Lewandowski <k.lewandowsk@samsung.com>
Thu, 10 Aug 2017 13:01:07 +0000 (15:01 +0200)
committerKarol Lewandowski <k.lewandowsk@samsung.com>
Fri, 11 Aug 2017 10:38:13 +0000 (12:38 +0200)
Change-Id: I63cd978a022789267a8081166ebdad508ead8273
Signed-off-by: Karol Lewandowski <k.lewandowsk@samsung.com>
include/log_file.h
src/logger/logger.c
src/logutil/logutil.c
src/shared/log_file.c

index b98ce84..0157bc9 100644 (file)
 
 #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 */
index 8313731..66766a6 100644 (file)
@@ -813,15 +813,22 @@ static void buffer_append(struct logger* s, const struct logger_entry* entry, st
  * @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;
 }
 
 /**
@@ -903,7 +910,7 @@ static int print_out_logs(struct logger *server, struct reader *reader)
                        reader->bytes_to_read -= ple->len;
 
                if (plaintext) {
-                       write_with_rotation(ple, &reader->file);
+                       logfile_write_with_rotation(ple, &reader->file);
                        continue;
                }
 
@@ -941,17 +948,11 @@ static int print_out_logs(struct logger *server, struct reader *reader)
                        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);
                }
        }
 
@@ -988,15 +989,11 @@ static void writer_close_fd(struct logger* server, struct writer* wr)
  */
 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);
 }
 
@@ -1039,7 +1036,7 @@ static int service_reader_file(struct logger * server, struct reader* 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);
                }
        }
 
@@ -1140,8 +1137,7 @@ static int parse_command_line(const char* cmdl, struct writer* wr, struct reader
        char *tok;
        char *tok_sv;
        int retval = 0;
-       struct reader * reader;
-       struct stat stat_buf;
+       struct reader *reader;
        int silence = 0;
 
        if (!cmdl)
@@ -1165,12 +1161,11 @@ static int parse_command_line(const char* cmdl, struct writer* wr, struct reader
        }
 
        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;
@@ -1257,32 +1252,11 @@ static int parse_command_line(const char* cmdl, struct writer* wr, struct reader
        }
 
        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;
index 43f23d5..17055d2 100755 (executable)
@@ -119,15 +119,6 @@ static inline void fdi_array_free(void *pointer)
        }
 }
 
-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;
@@ -185,7 +176,7 @@ static int push_log(struct logger_entry * p, struct log_file *l_file, struct sor
                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);
        }
 
@@ -381,7 +372,7 @@ static int process_log(struct logger_entry *e, struct logger_entry *last, struct
        }
 
        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;
@@ -554,7 +545,7 @@ static void handle_pipe(struct fd_info **data_fds, int fd_count, int dump, struc
                                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;
@@ -732,7 +723,7 @@ cleanup:
        return ret;
 }
 
-int main(int argc, char ** argv)
+int main(int argc, char **argv)
 {
        char* buffer_names[SIMULTANEOUS_BUFFERS];
        int buffer_cnt = 0;
@@ -748,21 +739,18 @@ int main(int argc, char ** argv)
        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");
@@ -813,7 +801,9 @@ int main(int argc, char ** argv)
                        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));
@@ -867,13 +857,10 @@ int main(int argc, char ** argv)
 
        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);
 
@@ -883,24 +870,10 @@ int main(int argc, char ** argv)
                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) {
@@ -932,6 +905,10 @@ int main(int argc, char ** argv)
        handle_pipe(fdi_ptrs, fdi_cnt, dump, &logs, &l_file);
 
        return 0;
+
+err_nomem:
+       printf("Unable to allocate memory\n");
+       return 1;
 }
 
 /**
index a8801e5..51b3c96 100644 (file)
 #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;
 }
 
 /**
@@ -54,13 +183,15 @@ void open_logfile(struct log_file *file)
  * @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)
@@ -70,9 +201,9 @@ void rotate_logs(struct log_file *file)
                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);
 }
 
 /**
@@ -82,7 +213,7 @@ void rotate_logs(struct log_file *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))
@@ -91,8 +222,9 @@ int write_with_rotation(struct logger_entry* e, struct log_file* file)
        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;
 }