+#include "conf.h"
+#include "crypto.h"
+#include "event.h"
+#include "logger.h"
+#include "names.h"
+#include "net.h"
+#include "process.h"
+#include "protocol.h"
+#include "utils.h"
+#include "xalloc.h"
+#include "version.h"
+#include "random.h"
+#include "sandbox.h"
+#include "watchdog.h"
+
+/* If nonzero, display usage information and exit. */
+static bool show_help = false;
+
+/* If nonzero, print the version on standard output and exit. */
+static bool show_version = false;
+
+#ifdef HAVE_MLOCKALL
+/* If nonzero, disable swapping for this process. */
+static bool do_mlock = false;
+#endif
+
+#ifndef HAVE_WINDOWS
+/* If nonzero, chroot to netdir after startup. */
+static bool do_chroot = false;
+
+/* If !NULL, do setuid to given user after startup */
+static const char *switchuser = NULL;
+#endif
+
+char **g_argv; /* a copy of the cmdline arguments */
+
+static int status = 1;
+
+typedef enum option_t {
+ OPT_BAD_OPTION = '?',
+ OPT_LONG_OPTION = 0,
+
+ // Short options
+ OPT_CONFIG_FILE = 'c',
+ OPT_NETNAME = 'n',
+ OPT_NO_DETACH = 'D',
+ OPT_DEBUG = 'd',
+ OPT_MLOCK = 'L',
+ OPT_CHROOT = 'R',
+ OPT_CHANGE_USER = 'U',
+ OPT_SYSLOG = 's',
+ OPT_OPTION = 'o',
+
+ // Long options
+ OPT_HELP = 255,
+ OPT_VERSION,
+ OPT_NO_SECURITY,
+ OPT_LOGFILE,
+ OPT_PIDFILE,
+} option_t;
+
+static struct option const long_options[] = {
+ {"config", required_argument, NULL, OPT_CONFIG_FILE},
+ {"net", required_argument, NULL, OPT_NETNAME},
+ {"no-detach", no_argument, NULL, OPT_NO_DETACH},
+ {"debug", optional_argument, NULL, OPT_DEBUG},
+ {"mlock", no_argument, NULL, OPT_MLOCK},
+ {"chroot", no_argument, NULL, OPT_CHROOT},
+ {"user", required_argument, NULL, OPT_CHANGE_USER},
+ {"syslog", no_argument, NULL, OPT_SYSLOG},
+ {"option", required_argument, NULL, OPT_OPTION},
+ {"help", no_argument, NULL, OPT_HELP},
+ {"version", no_argument, NULL, OPT_VERSION},
+ {"bypass-security", no_argument, NULL, OPT_NO_SECURITY},
+ {"logfile", optional_argument, NULL, OPT_LOGFILE},
+ {"pidfile", required_argument, NULL, OPT_PIDFILE},
+ {NULL, 0, NULL, 0},
+};
+
+#ifdef HAVE_WINDOWS
+static struct WSAData wsa_state;
+int main2(int argc, char **argv);
+#endif
+
+static void usage(bool status) {
+ if(status)
+ fprintf(stderr, "Try `%s --help\' for more information.\n",
+ program_name);
+ else {
+ fprintf(stdout,
+ "Usage: %s [option]...\n"
+ "\n"
+ " -c, --config=DIR Read configuration options from DIR.\n"
+ " -D, --no-detach Don't fork and detach.\n"
+ " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n"
+ " -n, --net=NETNAME Connect to net NETNAME.\n"
+#ifdef HAVE_MLOCKALL
+ " -L, --mlock Lock tinc into main memory.\n"
+#endif
+ " --logfile[=FILENAME] Write log entries to a logfile.\n"
+ " -s --syslog Use syslog instead of stderr with --no-detach.\n"
+ " --pidfile=FILENAME Write PID and control socket cookie to FILENAME.\n"
+ " --bypass-security Disables meta protocol security, for debugging.\n"
+ " -o, --option[HOST.]KEY=VALUE Set global/host configuration value.\n"
+#ifndef HAVE_WINDOWS
+ " -R, --chroot chroot to NET dir at startup.\n"
+ " -U, --user=USER setuid to given USER at startup.\n"
+#endif
+ " --help Display this help and exit.\n"
+ " --version Output version information and exit.\n"
+ "\n"
+ "Report bugs to tinc@tinc-vpn.org.\n",
+ program_name);
+ }
+}
+
+// Try to resolve path to absolute, return a copy of the argument if this fails.
+static char *get_path_arg(char *arg) {
+ char *result = absolute_path(arg);
+
+ if(!result) {
+ result = xstrdup(arg);
+ }
+
+ return result;
+}
+
+static bool parse_options(int argc, char **argv) {
+ config_t *cfg;
+ int r;
+ int option_index = 0;
+ int lineno = 0;
+
+ while((r = getopt_long(argc, argv, "c:DLd::n:so:RU:", long_options, &option_index)) != EOF) {
+ switch((option_t) r) {
+ case OPT_LONG_OPTION:
+ break;
+
+ case OPT_BAD_OPTION:
+ usage(true);
+ goto exit_fail;
+
+ case OPT_CONFIG_FILE:
+ assert(optarg);
+ free(confbase);
+ confbase = get_path_arg(optarg);
+ break;
+
+ case OPT_NO_DETACH:
+ do_detach = false;
+ break;
+
+ case OPT_MLOCK: /* lock tincd into RAM */
+#ifndef HAVE_MLOCKALL
+ logger(DEBUG_ALWAYS, LOG_ERR, "The %s option is not supported on this platform.", argv[optind - 1]);
+ goto exit_fail;