Add "network" command to list or switch networks.
[tinc] / src / tincctl.c
index 956771f..fdb72e0 100644 (file)
@@ -1,6 +1,6 @@
 /*
     tincctl.c -- Controlling a running tincd
-    Copyright (C) 2007-2013 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2014 Guus Sliepen <guus@tinc-vpn.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -67,10 +67,7 @@ bool confbasegiven = false;
 bool netnamegiven = false;
 char *scriptinterpreter = NULL;
 char *scriptextension = "";
-
-#ifdef HAVE_MINGW
-static struct WSAData wsa_state;
-#endif
+static char *prompt;
 
 static struct option const long_options[] = {
        {"config", required_argument, NULL, 'c'},
@@ -141,6 +138,7 @@ static void usage(bool status) {
                                "  exchange-all [--force]     Same as export-all followed by import\n"
                                "  invite NODE [...]          Generate an invitation for NODE\n"
                                "  join INVITATION            Join a VPN using an INVITIATION\n"
+                               "  network [NETNAME]          List all known networks, or switch to the one named NETNAME.\n"
                                "\n");
                printf("Report bugs to tinc@tinc-vpn.org.\n");
        }
@@ -312,8 +310,7 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
        /* Check stdin and stdout */
        if(ask && tty) {
                /* Ask for a file and/or directory name. */
-               fprintf(stdout, "Please enter a file to save %s to [%s]: ", what, filename);
-               fflush(stdout);
+               fprintf(stderr, "Please enter a file to save %s to [%s]: ", what, filename);
 
                if(fgets(buf, sizeof buf, stdin) == NULL) {
                        fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
@@ -682,14 +679,6 @@ bool connect_tincd(bool verbose) {
 
        fclose(f);
 
-#ifdef HAVE_MINGW
-       if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
-               if(verbose)
-                       fprintf(stderr, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
-               return false;
-       }
-#endif
-
 #ifndef HAVE_MINGW
        struct sockaddr_un sa;
        sa.sun_family = AF_UNIX;
@@ -1304,6 +1293,7 @@ const var_t variables[] = {
        {"IffOneQueue", VAR_SERVER},
        {"Interface", VAR_SERVER},
        {"KeyExpire", VAR_SERVER},
+       {"ListenAddress", VAR_SERVER | VAR_MULTIPLE},
        {"LocalDiscovery", VAR_SERVER},
        {"MACExpire", VAR_SERVER},
        {"MaxConnectionBurst", VAR_SERVER},
@@ -1618,7 +1608,7 @@ static int cmd_config(int argc, char *argv[]) {
        if(action < 0 && !removed) {
                remove(tmpfile);
                fprintf(stderr, "No configuration variables deleted.\n");
-               return *value;
+               return *value != 0;
        }
 
        // Replace the configuration file with the new one
@@ -1722,8 +1712,7 @@ static int cmd_init(int argc, char *argv[]) {
        } else if(argc < 2) {
                if(tty) {
                        char buf[1024];
-                       fprintf(stdout, "Enter the Name you want your tinc node to have: ");
-                       fflush(stdout);
+                       fprintf(stderr, "Enter the Name you want your tinc node to have: ");
                        if(!fgets(buf, sizeof buf, stdin)) {
                                fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
                                return 1;
@@ -1751,7 +1740,7 @@ static int cmd_init(int argc, char *argv[]) {
                return 1;
        }
 
-       if(strcmp(confdir, confbase) && mkdir(confdir, 0755) && errno != EEXIST) {
+       if(!confbase_given && mkdir(confdir, 0755) && errno != EEXIST) {
                fprintf(stderr, "Could not create directory %s: %s\n", confdir, strerror(errno));
                return 1;
        }
@@ -1789,7 +1778,7 @@ static int cmd_init(int argc, char *argv[]) {
                        fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
                        return 1;
                }
-               fprintf(f, "#!/bin/sh\n\necho 'Unconfigured tinc-up script, please edit!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
+               fprintf(f, "#!/bin/sh\n\necho 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
                fclose(f);
        }
 #endif
@@ -2079,6 +2068,70 @@ static int cmd_exchange_all(int argc, char *argv[]) {
        return cmd_export_all(argc, argv) ?: cmd_import(argc, argv);
 }
 
+static int switch_network(char *name) {
+       if(fd >= 0) {
+               close(fd);
+               fd = -1;
+       }
+
+       free(confbase);
+       confbase = NULL;
+       free(pidfilename);
+       pidfilename = NULL;
+       free(logfilename);
+       logfilename = NULL;
+       free(unixsocketname);
+       unixsocketname = NULL;
+       free(tinc_conf);
+       free(hosts_dir);
+       free(prompt);
+
+       free(netname);
+       netname = strcmp(name, ".") ? xstrdup(name) : NULL;
+
+       make_names();
+        xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
+        xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
+       xasprintf(&prompt, "%s> ", identname);
+
+       return 0;
+}
+
+static int cmd_network(int argc, char *argv[]) {
+       if(argc > 2) {
+               fprintf(stderr, "Too many arguments!\n");
+               return 1;
+       }
+
+       if(argc == 2)
+               return switch_network(argv[1]);
+
+       DIR *dir = opendir(confdir);
+       if(!dir) {
+               fprintf(stderr, "Could not read directory %s: %s\n", confdir, strerror(errno));
+                return 1;
+        }
+
+       struct dirent *ent;
+       while((ent = readdir(dir))) {
+               if(*ent->d_name == '.')
+                       continue;
+
+               if(!strcmp(ent->d_name, "tinc.conf")) {
+                       printf(".\n");
+                       continue;
+               }
+
+               char *fname;
+               xasprintf(&fname, "%s/%s/tinc.conf", confdir, ent->d_name);
+               if(!access(fname, R_OK))
+                       printf("%s\n", ent->d_name);
+               free(fname);
+       }
+
+       return 0;
+}
+
 static const struct {
        const char *command;
        int (*function)(int argc, char *argv[]);
@@ -2118,6 +2171,7 @@ static const struct {
        {"exchange-all", cmd_exchange_all},
        {"invite", cmd_invite},
        {"join", cmd_join},
+       {"network", cmd_network},
        {NULL, NULL},
 };
 
@@ -2244,7 +2298,6 @@ static char **completion (const char *text, int start, int end) {
 #endif
 
 static int cmd_shell(int argc, char *argv[]) {
-       char *prompt;
        xasprintf(&prompt, "%s> ", identname);
        int result = 0;
        char buf[4096];
@@ -2366,6 +2419,15 @@ int main(int argc, char *argv[]) {
                return 0;
        }
 
+#ifdef HAVE_MINGW
+       static struct WSAData wsa_state;
+
+       if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
+               fprintf(stderr, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
+               return false;
+       }
+#endif
+
        srand(time(NULL));
        crypto_init();