From: Michael Tremer Date: Wed, 29 Jan 2025 11:09:44 +0000 (+0000) Subject: log file: Add new object to write a (compressed) log file X-Git-Tag: 0.9.30~307 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=707686a643d94c8d6ce0e3612868544183c17376;p=pakfire.git log file: Add new object to write a (compressed) log file Signed-off-by: Michael Tremer --- diff --git a/.gitignore b/.gitignore index 0954dac2..5cc5981a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ /tests/libpakfire/jail /tests/libpakfire/key /tests/libpakfire/log_buffer +/tests/libpakfire/log_file /tests/libpakfire/log_stream /tests/libpakfire/main /tests/libpakfire/makefile diff --git a/Makefile.am b/Makefile.am index 9db5b7c5..c6173e59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -237,6 +237,8 @@ libpakfire_la_SOURCES = \ src/pakfire/linter-file.h \ src/pakfire/log_buffer.c \ src/pakfire/log_buffer.h \ + src/pakfire/log_file.c \ + src/pakfire/log_file.h \ src/pakfire/log_stream.c \ src/pakfire/log_stream.h \ src/pakfire/logging.c \ @@ -573,6 +575,7 @@ check_PROGRAMS += \ tests/libpakfire/jail \ tests/libpakfire/key \ tests/libpakfire/log_buffer \ + tests/libpakfire/log_file \ tests/libpakfire/log_stream \ tests/libpakfire/makefile \ tests/libpakfire/os \ @@ -825,6 +828,21 @@ tests_libpakfire_log_buffer_LDFLAGS = \ tests_libpakfire_log_buffer_LDADD = \ $(TESTSUITE_LDADD) +tests_libpakfire_log_file_SOURCES = \ + tests/libpakfire/log_file.c + +tests_libpakfire_log_file_CPPFLAGS = \ + $(TESTSUITE_CPPFLAGS) + +tests_libpakfire_log_file_CFLAGS = \ + $(TESTSUITE_CFLAGS) + +tests_libpakfire_log_file_LDFLAGS = \ + $(TESTSUITE_LDFLAGS) + +tests_libpakfire_log_file_LDADD = \ + $(TESTSUITE_LDADD) + tests_libpakfire_log_stream_SOURCES = \ tests/libpakfire/log_stream.c diff --git a/src/pakfire/log_file.c b/src/pakfire/log_file.c new file mode 100644 index 00000000..12ea180b --- /dev/null +++ b/src/pakfire/log_file.c @@ -0,0 +1,167 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2025 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include + +#include +#include +#include +#include +#include + +struct pakfire_log_file { + struct pakfire_ctx* ctx; + int nrefs; + + // Flags + int flags; + + // Path + char path[PATH_MAX]; + + // File Handle + FILE* f; +}; + +static void pakfire_log_file_free(struct pakfire_log_file* self) { + // Close the log file + pakfire_log_file_close(self); + + // Free all held resources + if (*self->path) + unlink(self->path); + if (self->ctx) + pakfire_ctx_unref(self->ctx); + free(self); +} + +int pakfire_log_file_create(struct pakfire_log_file** file, struct pakfire_ctx* ctx, int flags) { + struct pakfire_log_file* self = NULL; + int r; + + // Allocate some memory + self = calloc(1, sizeof(*self)); + if (!self) + return -errno; + + // Store the context + self->ctx = pakfire_ctx_ref(ctx); + + // Initialize the reference counter + self->nrefs = 1; + + // Store flags + self->flags = flags; + + // Make some path + r = pakfire_string_set(self->path, PAKFIRE_TMP_DIR "/pakfire-log.XXXXXX"); + if (r < 0) + goto ERROR; + + // Create a new temporary file + self->f = pakfire_mktemp(self->path, 0600); + if (!self->f) { + r = -errno; + goto ERROR; + } + + // If we want to write the log file compressed, we replace the file handle + if (self->flags & PAKFIRE_LOG_FILE_COMPRESS) { + self->f = pakfire_zstdfopen(self->f, "w"); + if (!self->f) { + ERROR(self->ctx, "Could not enable compression for log file: %m\n"); + r = -errno; + goto ERROR; + } + } + + DEBUG(self->ctx, "Created log file %s\n", self->path); + + // Return the pointer + *file = self; + return 0; + +ERROR: + pakfire_log_file_free(self); + + return r; +} + +struct pakfire_log_file* pakfire_log_file_ref(struct pakfire_log_file* self) { + self->nrefs++; + + return self; +} + +struct pakfire_log_file* pakfire_log_file_unref(struct pakfire_log_file* self) { + if (--self->nrefs > 0) + return self; + + pakfire_log_file_free(self); + return NULL; +} + +const char* pakfire_log_file_path(struct pakfire_log_file* self) { + return self->path; +} + +int pakfire_log_file_close(struct pakfire_log_file* self) { + int r; + + if (self->f) { + r = fclose(self->f); + if (r < 0) { + ERROR(self->ctx, "Could not close log file: %s\n", strerror(-r)); + return r; + } + + DEBUG(self->ctx, "Closed log file %s\n", self->path); + + self->f = NULL; + } + + return 0; +} + +int pakfire_log_file_write(struct pakfire_log_file* self, const char* buffer, ssize_t length) { + int r; + + // Check inputs + if (unlikely(!buffer)) + return -EINVAL; + + // Check if the file is still open + if (unlikely(!self->f)) + return -EBADF; + + // Automatically determine the length + if (unlikely(length < 0)) + length = strlen(buffer); + + // Write the buffer to the file + r = fwrite(buffer, 1, length, self->f); + if (unlikely(r < length)) { + ERROR(self->ctx, "Could not write to log file: %m\n"); + return -errno; + } + + return 0; +} diff --git a/src/pakfire/log_file.h b/src/pakfire/log_file.h new file mode 100644 index 00000000..6e9b3cf9 --- /dev/null +++ b/src/pakfire/log_file.h @@ -0,0 +1,47 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2025 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_LOG_FILE_H +#define PAKFIRE_LOG_FILE_H + +#include + +/* + Writes the log into a compressed file +*/ + +struct pakfire_log_file; + +enum pakfire_log_file_flags { + PAKFIRE_LOG_FILE_COMPRESS = (1 << 0), +}; + +int pakfire_log_file_create(struct pakfire_log_file** file, + struct pakfire_ctx* ctx, int flags); +struct pakfire_log_file* pakfire_log_file_ref(struct pakfire_log_file* self); +struct pakfire_log_file* pakfire_log_file_unref(struct pakfire_log_file* self); + +const char* pakfire_log_file_path(struct pakfire_log_file* self); + +int pakfire_log_file_close(struct pakfire_log_file* self); + +int pakfire_log_file_write(struct pakfire_log_file* self, const char* buffer, ssize_t length); + +#endif /* PAKFIRE_LOG_FILE_H */ diff --git a/tests/libpakfire/log_file.c b/tests/libpakfire/log_file.c new file mode 100644 index 00000000..3c22ea7c --- /dev/null +++ b/tests/libpakfire/log_file.c @@ -0,0 +1,74 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2025 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include +#include +#include + +#include "../testsuite.h" + +static int __test_simple(const struct test* t, int flags) { + struct pakfire_log_file* file = NULL; + char path[PATH_MAX] = ""; + int r = EXIT_FAILURE; + + // Create a new log file + ASSERT_SUCCESS(pakfire_log_file_create(&file, t->ctx, flags)); + + // Store a copy of the path + ASSERT_SUCCESS(pakfire_string_set(path, pakfire_log_file_path(file))); + + // Write something to the file + for (int i = 0; i < 10; i++) + ASSERT_SUCCESS(pakfire_log_file_write(file, "BUFFER DATA\n", -1)); + + // Everything passed + r = EXIT_SUCCESS; + +FAIL: + if (file) + pakfire_log_file_unref(file); + + // Check if the log file was removed + if (*path) { + if (pakfire_path_exists(path)) { + LOG("Log file was not cleaned up\n"); + return 1; + } + } + + return r; +} + +static int test_uncompressed(const struct test* t) { + return __test_simple(t, 0); +} + +static int test_compressed(const struct test* t) { + return __test_simple(t, PAKFIRE_LOG_FILE_COMPRESS); +} + +int main(int argc, const char* argv[]) { + testsuite_add_test(test_uncompressed, 0); + testsuite_add_test(test_compressed, 0); + + return testsuite_run(argc, argv); +}