summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c184
1 files changed, 172 insertions, 12 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.