diff options
Diffstat (limited to 'log.c')
-rw-r--r-- | log.c | 104 |
1 files changed, 75 insertions, 29 deletions
diff --git a/log.c b/log.c index c114c41..d6b3f2a 100644 --- a/log.c +++ b/log.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * 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 @@ -27,16 +27,60 @@ #include <assert.h> #include <err.h> +#include <errno.h> +#include <fcntl.h> #include <limits.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> #include <sysexits.h> #include <time.h> +#include <unistd.h> + +#ifdef __FreeBSD__ +#include <capsicum_helpers.h> +#endif #include "chat.h" -bool logEnable; +static int logDir = -1; + +void logOpen(void) { + char buf[PATH_MAX]; + int error = mkdir(dataPath(buf, sizeof(buf), "", 0), S_IRWXU); + if (error && errno != EEXIST) err(EX_CANTCREAT, "%s", buf); + + error = mkdir(dataPath(buf, sizeof(buf), "log", 0), S_IRWXU); + if (error && errno != EEXIST) err(EX_CANTCREAT, "%s", buf); + + logDir = open(buf, O_RDONLY | O_CLOEXEC); + if (logDir < 0) err(EX_CANTCREAT, "%s", buf); + +#ifdef __FreeBSD__ + cap_rights_t rights; + cap_rights_init( + &rights, CAP_MKDIRAT, CAP_CREATE, CAP_WRITE, + /* for fdopen(3) */ CAP_FCNTL, CAP_FSTAT + ); + error = caph_rights_limit(logDir, &rights); + if (error) err(EX_OSERR, "cap_rights_limit"); +#endif +} + +static void logMkdir(const char *path) { + int error = mkdirat(logDir, path, S_IRWXU); + if (error && errno != EEXIST) err(EX_CANTCREAT, "log/%s", path); +} + +static void sanitize(char *ptr, char *end) { + for (char *ch = ptr; ch < end && *ch == '.'; ++ch) { + *ch = '_'; + } + for (char *ch = ptr; ch < end; ++ch) { + if (*ch == '/') *ch = '_'; + } +} static struct { int year; @@ -62,44 +106,46 @@ static FILE *logFile(uint id, const struct tm *tm) { logs[id].month = tm->tm_mon; logs[id].day = tm->tm_mday; - char path[PATH_MAX] = "log"; - size_t len = strlen(path); - dataMkdir(""); - dataMkdir(path); + char path[PATH_MAX]; + char *ptr = path, *end = &path[sizeof(path)]; - path[len++] = '/'; - for (const char *ch = network.name; *ch; ++ch) { - path[len++] = (*ch == '/' ? '_' : *ch); - } - path[len] = '\0'; - dataMkdir(path); + ptr = seprintf(ptr, end, "%s", network.name); + sanitize(path, ptr); + logMkdir(path); - path[len++] = '/'; - for (const char *ch = idNames[id]; *ch; ++ch) { - path[len++] = (*ch == '/' ? '_' : *ch); - } - path[len] = '\0'; - dataMkdir(path); + char *name = ptr; + ptr = seprintf(ptr, end, "/%s", idNames[id]); + sanitize(&name[1], ptr); + logMkdir(path); + + size_t len = strftime(ptr, end - ptr, "/%F.log", tm); + if (!len) errx(EX_CANTCREAT, "log path too long"); - strftime(&path[len], sizeof(path) - len, "/%F.log", tm); - logs[id].file = dataOpen(path, "a"); - if (!logs[id].file) exit(EX_CANTCREAT); + int fd = openat( + logDir, path, + O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, + S_IRUSR | S_IWUSR + ); + if (fd < 0) err(EX_CANTCREAT, "log/%s", path); + logs[id].file = fdopen(fd, "a"); + if (!logs[id].file) err(EX_OSERR, "fdopen"); setlinebuf(logs[id].file); return logs[id].file; } void logClose(void) { - if (!logEnable) return; + if (logDir < 0) return; for (uint id = 0; id < IDCap; ++id) { if (!logs[id].file) continue; int error = fclose(logs[id].file); if (error) err(EX_IOERR, "%s", idNames[id]); } + close(logDir); } void logFormat(uint id, const time_t *src, const char *format, ...) { - if (!logEnable) return; + if (logDir < 0) return; time_t ts = (src ? *src : time(NULL)); struct tm *tm = localtime(&ts); @@ -109,15 +155,15 @@ void logFormat(uint id, const time_t *src, const char *format, ...) { char buf[sizeof("0000-00-00T00:00:00+0000")]; strftime(buf, sizeof(buf), "%FT%T%z", tm); - fprintf(file, "[%s] ", buf); - if (ferror(file)) err(EX_IOERR, "%s", idNames[id]); + int n = fprintf(file, "[%s] ", buf); + if (n < 0) err(EX_IOERR, "%s", idNames[id]); va_list ap; va_start(ap, format); - vfprintf(file, format, ap); + n = vfprintf(file, format, ap); va_end(ap); - if (ferror(file)) err(EX_IOERR, "%s", idNames[id]); + if (n < 0) err(EX_IOERR, "%s", idNames[id]); - fprintf(file, "\n"); - if (ferror(file)) err(EX_IOERR, "%s", idNames[id]); + n = fprintf(file, "\n"); + if (n < 0) err(EX_IOERR, "%s", idNames[id]); } |