From 7a631d32c72a0290792d8cd20f2b5d6e3f0af9e5 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Wed, 17 Jun 2020 15:19:57 +0200 Subject: Add some more basic options, and improve logging a bit more --- main.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- main.h | 24 ++++----- 2 files changed, 184 insertions(+), 24 deletions(-) diff --git a/main.c b/main.c index 598b9b2..7b14654 100644 --- a/main.c +++ b/main.c @@ -30,19 +30,127 @@ #define DEFAULT_HOMEDIR_PATH "/home/david/intest" #define DEFAULT_MAIN_CONFIG_FILE_PATH "./mcproxy.conf" +/* Global, not in struct cfg since they're too low-level */ +bool exiting = false; unsigned debug_mask = DBG_ERROR | DBG_INFO; -bool exiting = false; +/* Local */ +static bool daemonize = false; +static FILE *log_file = NULL; +static const char *log_file_path = NULL; +static struct cfg *cfghack = NULL; + +#define ANSI_RED "\x1B[0;31m" +#define ANSI_GREEN "\x1B[0;32m" +#define ANSI_YELLOW "\x1B[0;33m" +#define ANSI_BLUE "\x1B[0;34m" +#define ANSI_MAGENTA "\x1B[0;35m" +#define ANSI_GREY "\x1B[0;38;5;245m" +#define ANSI_NORMAL "\x1B[0m" + +static void +msg(enum debug_lvl lvl, const char *fmt, va_list ap) +{ + static bool first = true; + static bool use_colors = false; + static bool sd_daemon = false; + const char *color; + const char *sd_lvl; + + while (first) { + int fd; + const char *e; + + first = false; + + /* assume we're not launched by systemd when daemonized */ + if (daemonize) { + sd_daemon = false; + use_colors = false; + break; + } + + if (log_file) { + sd_daemon = false; + use_colors = false; + break; + } + + if (getenv("NO_COLOR")) { + sd_daemon = false; + use_colors = false; + break; + } + + fd = fileno(stderr); + if (fd < 0) { + /* Umm... */ + sd_daemon = true; + use_colors = false; + break; + } + + if (!isatty(fd)) { + sd_daemon = true; + use_colors = false; + break; + } + + /* systemd wouldn't normally set TERM */ + e = getenv("TERM"); + if (!e) { + sd_daemon = true; + use_colors = false; + break; + } + + if (!strcmp(e, "dumb")) { + sd_daemon = false; + use_colors = false; + break; + } + + sd_daemon = false; + use_colors = true; + } + + switch (lvl) { + case DBG_ERROR: + sd_lvl = SD_ERR; + color = use_colors ? ANSI_RED : NULL; + break; + case DBG_VERBOSE: + sd_lvl = SD_INFO; + color = NULL; + break; + case DBG_INFO: + sd_lvl = SD_NOTICE; + color = NULL; + break; + default: + sd_lvl = SD_DEBUG; + color = use_colors ? ANSI_GREY : NULL; + break; + } -struct cfg *cfghack = NULL; + if (sd_daemon) + fprintf(stderr, sd_lvl); + else if (color) + fprintf(stderr, color); + + vfprintf(log_file ? log_file : stderr, fmt, ap); + + if (color) + fprintf(stderr, ANSI_NORMAL); +} void -__debug(enum debug_category category, const char *fmt, ...) +__debug(enum debug_lvl lvl, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - vfprintf(stdout, fmt, ap); + msg(lvl, fmt, ap); va_end(ap); } @@ -52,8 +160,9 @@ __die(const char *fmt, ...) va_list ap; va_start(ap, fmt); - vfprintf(stderr, fmt, ap); + msg(DBG_ERROR, fmt, ap); va_end(ap); + sd_notifyf(0, "STATUS=Error, shutting down\n"); exit(EXIT_FAILURE); }; @@ -219,6 +328,29 @@ const struct { } }; +static void +usage(int argc, char **argv, bool invalid) +{ + if (invalid) + info("Invalid option(s)\n"); + + info("Usage: %s [OPTIONS]\n" + "\n" + "Valid options:\n" + " -h, --homedir=DIR\tlook for configuration files in DIR\n" + " -u, --user=USER\trun as USER\n" + " -D, --daemonize\trun in daemon mode (disables stderr output)\n" + " -l, --logfile=FILE\tlog to FILE instead of stderr\n" + " -h, --help\t\tprint this information\n" + " -v, --verbose\t\tenable verbose logging\n" + " -d, --debug=CATEGORY\tenable debugging for CATEGORY\n" + "\t\t\t(use \"list\" to see available categories,\n" + "\t\t\t or \"all\" to enable all categories)\n", + argv[0]); + + exit(invalid ? EXIT_FAILURE : EXIT_SUCCESS); +} + static struct cfg * cfg_init(int argc, char **argv) { @@ -238,25 +370,38 @@ cfg_init(int argc, char **argv) while (true) { int option_index = 0; static struct option long_options[] = { - { "homedir", required_argument, 0, 'h' }, - { "debug", required_argument, 0, 'd' }, + { "homedir", required_argument, 0, 'H' }, + { "user", required_argument, 0, 'u' }, + { "daemonize", no_argument, 0, 'D' }, + { "logfile", required_argument, 0, 'l' }, + { "help", no_argument, 0, 'h' }, { "verbose", no_argument, 0, 'v' }, - { "user", required_argument, 0, 'v' }, + { "debug", required_argument, 0, 'd' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, ":h:d:vu:", + c = getopt_long(argc, argv, ":H:u:Dl:hvd:", long_options, &option_index); if (c == -1) break; switch (c) { - case 'h': + case 'H': cfg->homedir = optarg; break; + case 'v': debug_mask |= DBG_VERBOSE; break; + + case 'D': + daemonize = true; + break; + + case 'l': + log_file_path = optarg; + break; + case 'u': { struct passwd *pwd; @@ -301,14 +446,18 @@ cfg_init(int argc, char **argv) debug_mask |= debug_category_str[i].val; break; + + case 'h': + usage(argc, argv, false); + default: - die("invalid arguments"); + usage(argc, argv, true); } } if (optind < argc) - die("invalid arguments"); + usage(argc, argv, true); if (!cfg->homedir) cfg->homedir = DEFAULT_HOMEDIR_PATH; @@ -343,6 +492,17 @@ cfg_apply(struct cfg *cfg) setgroups(0, NULL); } + if (daemonize) { + if (daemon(1, 0) < 0) + die("daemon() failed: %m"); + } + + if (log_file_path) { + log_file = fopen(log_file_path, "ae"); + if (!log_file) + die("fopen(%s) failed: %m", log_file_path); + } + /* * Do this after caps have been dropped to make sure we're not * accessing a directory we should have permissions to. diff --git a/main.h b/main.h index 282d827..4de0884 100644 --- a/main.h +++ b/main.h @@ -12,7 +12,7 @@ extern bool exiting; extern unsigned debug_mask; -enum debug_category { +enum debug_lvl { DBG_ERROR = (0x1 << 1), DBG_INFO = (0x1 << 2), DBG_VERBOSE = (0x1 << 3), @@ -31,31 +31,31 @@ enum debug_category { }; static inline bool -debug_enabled(enum debug_category category) +debug_enabled(enum debug_lvl lvl) { - return !!(category & debug_mask); + return !!(lvl & debug_mask); } -void __debug(enum debug_category category, const char *fmt, ...) __attribute__((format(printf, 2, 3))); +void __debug(enum debug_lvl lvl, const char *fmt, ...) __attribute__((format(printf, 2, 3))); -#define __ifdebug(c, fmt, ...) \ - do { \ - if (debug_enabled((c))) \ - __debug((c), fmt __VA_OPT__(,) __VA_ARGS__); \ +#define __ifdebug(lvl, fmt, ...) \ + do { \ + if (debug_enabled((lvl))) \ + __debug((lvl), fmt __VA_OPT__(,) __VA_ARGS__); \ } while (0) -#define debug(c, fmt, ...) __ifdebug((c), "%s:%i: " fmt, __func__, \ +#define debug(lvl, fmt, ...) __ifdebug((lvl), "%s:%i: " fmt, __func__, \ __LINE__ __VA_OPT__(,) __VA_ARGS__) #define verbose(fmt, ...) __ifdebug(DBG_VERBOSE, fmt, __VA_ARGS__) -#define info(fmt, ...) __ifdebug(DBG_ERROR, fmt, __VA_ARGS__) +#define info(fmt, ...) __ifdebug(DBG_INFO, fmt, __VA_ARGS__) #define error(fmt, ...) __ifdebug(DBG_ERROR, "%s: " fmt, \ __func__ __VA_OPT__(,) __VA_ARGS__) void __die(const char *fmt, ...) __attribute__((format(printf, 1, 2))); -#define die(fmt, ...) __die("%s:%i: " fmt "\n", __func__, \ +#define die(fmt, ...) __die("%s:%i: " fmt "\n", __func__, \ __LINE__ __VA_OPT__(,) __VA_ARGS__) -#define perrordie(fmt, ...) __die("%s:%i: " fmt ": %m\n", __func__, \ +#define perrordie(fmt, ...) __die("%s:%i: " fmt ": %m\n", __func__, \ __LINE__ __VA_OPT__(,) __VA_ARGS__) struct uring_task; -- cgit v1.2.3