From 646c834492a419a96b4032c230e842d27f87e997 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 14 Feb 2021 10:01:02 -0500 Subject: [PATCH] Log to /var/log/apk.log This adds a log file at /var/log/apk.log. On each run, apk's version information and the current date & time are written to this file, followed by any normal apk output. --- doc/apk.8.scd | 2 ++ src/apk.c | 13 ++++++++----- src/apk_print.h | 7 ++++++- src/context.c | 16 ++++++++++++++++ src/print.c | 33 +++++++++++++++++++++++++++++---- 5 files changed, 61 insertions(+), 10 deletions(-) diff --git a/doc/apk.8.scd b/doc/apk.8.scd index 0ca26b1..caf8382 100644 --- a/doc/apk.8.scd +++ b/doc/apk.8.scd @@ -15,6 +15,8 @@ to install is called the _world_ (see *apk-world*(5)). *apk* supports various sub-commands to query and manipulate _world_ and local & remote package repositories. +All apk commands which modify the database are logged to /var/log/apk.log. + # COMMANDS Each command is documented in detail on its manual page. diff --git a/src/apk.c b/src/apk.c index 1141180..3de5ca4 100644 --- a/src/apk.c +++ b/src/apk.c @@ -46,11 +46,11 @@ time_t time(time_t *tloc) } #endif -static void version(struct apk_out *out) +static void version(struct apk_out *out, const char *prefix) { - apk_out(out, "apk-tools " APK_VERSION ", compiled for " APK_DEFAULT_ARCH "."); + apk_out_fmt(out, prefix, "apk-tools " APK_VERSION ", compiled for " APK_DEFAULT_ARCH "."); #ifdef TEST_MODE - apk_out(out, "TEST MODE BUILD. NOT FOR PRODUCTION USE."); + apk_out_fmt(out, prefix, "TEST MODE BUILD. NOT FOR PRODUCTION USE."); #endif } @@ -122,7 +122,7 @@ static int option_parse_global(void *ctx, struct apk_ctx *ac, int opt, const cha ac->out.verbosity++; break; case OPT_GLOBAL_version: - version(out); + version(out, NULL); return -ESHUTDOWN; case OPT_GLOBAL_force: ac->force |= APK_FORCE_OVERWRITE | APK_FORCE_OLD_APK @@ -260,7 +260,7 @@ const struct apk_option_group optgroup_commit = { static int usage(struct apk_out *out, struct apk_applet *applet) { - version(out); + version(out, NULL); apk_applet_help(applet, out); return 1; } @@ -460,6 +460,9 @@ int main(int argc, char **argv) r = apk_ctx_prepare(&ctx); if (r != 0) goto err; + apk_out_log_argv(&ctx.out, apk_argv); + version(&ctx.out, APK_OUT_LOG_ONLY); + if (ctx.open_flags) { r = apk_db_open(&db, &ctx); if (r != 0) { diff --git a/src/apk_print.h b/src/apk_print.h index ec766ed..132fd8c 100644 --- a/src/apk_print.h +++ b/src/apk_print.h @@ -30,11 +30,15 @@ void apk_url_parse(struct apk_url_print *, const char *); struct apk_out { int verbosity; unsigned int width, last_change; - FILE *out, *err; + FILE *out, *err, *log; }; static inline int apk_out_verbosity(struct apk_out *out) { return out->verbosity; } +// Pass this as the prefix to skip logging to the console (but still write to +// the log file). +#define APK_OUT_LOG_ONLY ((const char*)-1) + #define apk_err(out, args...) do { apk_out_fmt(out, "ERROR: ", args); } while (0) #define apk_out(out, args...) do { apk_out_fmt(out, NULL, args); } while (0) #define apk_warn(out, args...) do { if (apk_out_verbosity(out) >= 0) { apk_out_fmt(out, "WARNING: ", args); } } while (0) @@ -44,6 +48,7 @@ static inline int apk_out_verbosity(struct apk_out *out) { return out->verbosity void apk_out_reset(struct apk_out *); void apk_out_fmt(struct apk_out *, const char *prefix, const char *format, ...); +void apk_out_log_argv(struct apk_out *, char **argv); struct apk_progress { struct apk_out *out; diff --git a/src/context.c b/src/context.c index a6d7e5d..32a284e 100644 --- a/src/context.c +++ b/src/context.c @@ -29,6 +29,7 @@ void apk_ctx_free(struct apk_ctx *ac) apk_trust_free(&ac->trust); apk_string_array_free(&ac->repository_list); apk_string_array_free(&ac->private_keys); + if (ac->out.log) fclose(ac->out.log); } int apk_ctx_prepare(struct apk_ctx *ac) @@ -53,6 +54,21 @@ int apk_ctx_prepare(struct apk_ctx *ac) apk_err(&ac->out, "Unable to open root: %s", apk_error_str(errno)); return -errno; } + + if (ac->open_flags & APK_OPENF_WRITE) { + const char *log_path = "var/log/apk.log", *log_dir = "var/log"; + const int lflags = O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC; + int fd = openat(ac->root_fd, log_path, lflags, 0644); + if (fd < 0 && (ac->open_flags & APK_OPENF_CREATE)) { + mkdirat(ac->root_fd, log_dir, 0755); + fd = openat(ac->root_fd, log_path, lflags, 0644); + } + if (fd < 0) { + apk_err(&ac->out, "Unable to open log: %s", apk_error_str(errno)); + return -errno; + } + ac->out.log = fdopen(fd, "a"); + } return 0; } diff --git a/src/print.c b/src/print.c index e9e1dfb..cc82c49 100644 --- a/src/print.c +++ b/src/print.c @@ -136,10 +136,35 @@ static void log_internal(FILE *dest, const char *prefix, const char *format, va_ void apk_out_fmt(struct apk_out *out, const char *prefix, const char *format, ...) { va_list va; - va_start(va, format); - log_internal(prefix ? out->err : out->out, prefix, format, va); - out->last_change++; - va_end(va); + if (prefix != APK_OUT_LOG_ONLY) { + va_start(va, format); + log_internal(prefix ? out->err : out->out, prefix, format, va); + out->last_change++; + va_end(va); + } + + if (out->log) { + va_start(va, format); + log_internal(out->log, prefix, format, va); + va_end(va); + } +} + +void apk_out_log_argv(struct apk_out *out, char **argv) +{ + char when[32]; + struct tm tm; + time_t now = time(NULL); + + if (!out->log) return; + fprintf(out->log, "\nRunning `"); + for (int i = 0; argv[i]; ++i) { + fprintf(out->log, "%s%s", argv[i], argv[i+1] ? " " : ""); + } + + gmtime_r(&now, &tm); + strftime(when, sizeof(when), "%Y-%m-%d %H:%M:%S", &tm); + fprintf(out->log, "` at %s\n", when); } void apk_print_progress(struct apk_progress *p, size_t done, size_t total)