+#ifdef HAVE_MINGW
+static struct WSAData wsa_state;
+CRITICAL_SECTION mutex;
+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 {
+ printf("Usage: %s [option]...\n\n", program_name);
+ printf(" -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"
+ " -k, --kill[=SIGNAL] Attempt to kill a running tincd and exit.\n"
+ " -n, --net=NETNAME Connect to net NETNAME.\n"
+ " -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n"
+ " -L, --mlock Lock tinc into main memory.\n"
+ " --logfile[=FILENAME] Write log entries to a logfile.\n"
+ " --pidfile=FILENAME Write PID to FILENAME.\n"
+ " -o, --option=[HOST.]KEY=VALUE Set global/host configuration value.\n"
+ " -R, --chroot chroot to NET dir at startup.\n"
+ " -U, --user=USER setuid to given USER at startup.\n"
+ " --help Display this help and exit.\n"
+ " --version Output version information and exit.\n\n");
+ printf("Report bugs to tinc@tinc-vpn.org.\n");
+ }
+}
+
+static bool parse_options(int argc, char **argv) {
+ config_t *cfg;
+ int r;
+ int option_index = 0;
+ int lineno = 0;
+
+ cmdline_conf = list_alloc((list_action_t)free_config);
+
+ while((r = getopt_long(argc, argv, "c:DLd::k::n:o:K::RU:", long_options, &option_index)) != EOF) {
+ switch(r) {
+ case 0: /* long option */
+ break;
+
+ case 'c': /* config file */
+ if(confbase) {
+ fprintf(stderr, "Only one configuration directory can be given.\n");
+ usage(true);
+ return false;
+ }
+
+ confbase = xstrdup(optarg);
+ break;
+
+ case 'D': /* no detach */
+ do_detach = false;
+ break;
+
+ case 'L': /* no detach */
+#ifndef HAVE_MLOCKALL
+ logger(LOG_ERR, "%s not supported on this platform", "mlockall()");
+ return false;
+#else
+ do_mlock = true;
+ break;
+#endif
+
+ case 'd': /* increase debug level */
+ if(!optarg && optind < argc && *argv[optind] != '-') {
+ optarg = argv[optind++];
+ }
+
+ if(optarg) {
+ debug_level = atoi(optarg);
+ } else {
+ debug_level++;
+ }
+
+ break;
+
+ case 'k': /* kill old tincds */
+#ifndef HAVE_MINGW
+ if(!optarg && optind < argc && *argv[optind] != '-') {
+ optarg = argv[optind++];
+ }
+
+ if(optarg) {
+ if(!strcasecmp(optarg, "HUP")) {
+ kill_tincd = SIGHUP;
+ } else if(!strcasecmp(optarg, "TERM")) {
+ kill_tincd = SIGTERM;
+ } else if(!strcasecmp(optarg, "KILL")) {
+ kill_tincd = SIGKILL;
+ } else if(!strcasecmp(optarg, "USR1")) {
+ kill_tincd = SIGUSR1;
+ } else if(!strcasecmp(optarg, "USR2")) {
+ kill_tincd = SIGUSR2;
+ } else if(!strcasecmp(optarg, "WINCH")) {
+ kill_tincd = SIGWINCH;
+ } else if(!strcasecmp(optarg, "INT")) {
+ kill_tincd = SIGINT;
+ } else if(!strcasecmp(optarg, "ALRM")) {
+ kill_tincd = SIGALRM;
+ } else if(!strcasecmp(optarg, "ABRT")) {
+ kill_tincd = SIGABRT;
+ } else {
+ kill_tincd = atoi(optarg);
+
+ if(!kill_tincd) {
+ fprintf(stderr, "Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n",
+ optarg);
+ usage(true);
+ return false;
+ }
+ }
+ } else {
+ kill_tincd = SIGTERM;
+ }
+
+#else
+ kill_tincd = 1;
+#endif
+ break;
+
+ case 'n': /* net name given */
+
+ /* netname "." is special: a "top-level name" */
+ if(netname) {
+ fprintf(stderr, "Only one netname can be given.\n");
+ usage(true);
+ return false;
+ }
+
+ if(optarg && strcmp(optarg, ".")) {
+ netname = xstrdup(optarg);
+ }
+
+ break;
+
+ case 'o': /* option */
+ cfg = parse_config_line(optarg, NULL, ++lineno);
+
+ if(!cfg) {
+ return false;
+ }
+
+ list_insert_tail(cmdline_conf, cfg);
+ break;
+
+ case 'K': /* generate public/private keypair */
+ if(!optarg && optind < argc && *argv[optind] != '-') {
+ optarg = argv[optind++];
+ }
+
+ if(optarg) {
+ generate_keys = atoi(optarg);
+
+ if(generate_keys < 512) {
+ fprintf(stderr, "Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n",
+ optarg);
+ usage(true);
+ return false;
+ }
+
+ generate_keys &= ~7; /* Round it to bytes */
+ } else {
+ generate_keys = 2048;
+ }
+
+ break;
+
+ case 'R': /* chroot to NETNAME dir */
+ do_chroot = true;
+ break;
+
+ case 'U': /* setuid to USER */
+ switchuser = optarg;
+ break;
+
+ case 1: /* show help */
+ show_help = true;
+ break;
+
+ case 2: /* show version */
+ show_version = true;
+ break;
+
+ case 3: /* bypass security */
+ bypass_security = true;
+ break;
+
+ case 4: /* write log entries to a file */
+ use_logfile = true;
+
+ if(!optarg && optind < argc && *argv[optind] != '-') {
+ optarg = argv[optind++];
+ }
+
+ if(optarg) {
+ if(logfilename) {
+ fprintf(stderr, "Only one logfile can be given.\n");
+ usage(true);
+ return false;
+ }
+
+ logfilename = xstrdup(optarg);
+ }
+
+ break;
+
+ case 5: /* write PID to a file */
+ if(pidfilename) {
+ fprintf(stderr, "Only one pidfile can be given.\n");
+ usage(true);
+ return false;
+ }
+
+ pidfilename = xstrdup(optarg);
+ break;
+
+ case '?':
+ usage(true);
+ return false;
+
+ default:
+ break;
+ }
+ }
+
+ if(optind < argc) {
+ fprintf(stderr, "%s: unrecognized argument '%s'\n", argv[0], argv[optind]);
+ usage(true);
+ return false;
+ }
+
+ return true;