/* SPDX-License-Identifier: GPL-2.0-only */ /* * debug.c - for debug and logging. * * Copyright (C) 2025 Genexis AB. * * Author: anjan.chanda@iopsys.eu * */ #include <stdlib.h> #include <stdio.h> #include <stdbool.h> #include <stdarg.h> #include <string.h> #include <syslog.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <time.h> #include <easy/easy.h> #include "wifimngr_opts.h" #include "debug.h" extern const char *PROG_NAME; static int loglevel; static uint32_t features; static const char *logfile; static FILE *outfile; static int ffd = -1; static int ofd = -1; static bool syslogging; static bool logfile_isfifo; static const int syslog_level[] = { LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG }; uint32_t logfeature_to_enum(const char *s) { if (!strncmp(s, "cmd", 3)) return BIT(LOG_CMD); if (!strncmp(s, "event", 5)) return BIT(LOG_EVENT); if (!strncmp(s, "default", 7)) return BIT(LOG_DEFAULT); if (!strncmp(s, "all", 3)) return LOG_FEATURE_ALL; return 0; } const char *logfeature_to_string(uint32_t e) { switch (e) { case LOG_CMD: return "cmd"; case LOG_EVENT: return "event"; case LOG_DEFAULT: return "default"; } return ""; } void restart_logging(void *args) { struct wifimngr_cmdline_opts *opts = args; syslogging = opts->syslogging; logfile = opts->logfile; logfile_isfifo = opts->logfile_isfifo; loglevel = opts->loglevel; features = opts->features; if (syslogging) openlog(PROG_NAME, 0, LOG_DAEMON); if (!logfile) { outfile = stderr; ofd = fileno(stderr); return; } if (logfile_isfifo) { struct stat st; int rfd; if (stat(logfile, &st)) unlink(logfile); mkfifo(logfile, 0600); if (stat(logfile, &st) == -1 || !S_ISFIFO(st.st_mode)) return; rfd = open(logfile, O_RDONLY | O_NONBLOCK); if (rfd) { ffd = open(logfile, O_WRONLY | O_NONBLOCK); close(rfd); } } else { ofd = open(logfile, O_CREAT | O_WRONLY | O_APPEND | O_NONBLOCK); } } void stop_logging(void) { if (syslogging) closelog(); if (outfile) fclose(outfile); if (ofd > 0) { close(ofd); ofd = -1; } if (ffd > 0) { close(ffd); unlink(logfile); } } static void log_timestamp(int fd) { time_t now = time(NULL); struct tm *tm_now = localtime(&now); const char *tm_fmt = "[%d-%02d-%02d %02d:%02d:%02d] "; dprintf(fd, tm_fmt, tm_now->tm_year + 1900, tm_now->tm_mon + 1, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec); } void log_message(int feature, int level, const char *fmt, ...) { va_list args; int fd = -1; if (!(BIT(feature) & features)) return; if (level > loglevel) return; va_start(args, fmt); if (syslogging && level >= 0) vsyslog(syslog_level[level > 3 ? 3 : level], fmt, args); if (logfile_isfifo && ffd > 0) fd = ffd; else if (ofd >= 0) fd = ofd; if (fd != -1) { log_timestamp(fd); dprintf(fd, "[%d]: ", getpid()); vdprintf(fd, fmt, args); } va_end(args); }