summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c184
-rw-r--r--main.h24
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;