Add an easy way to export and import host configuration files.
authorGuus Sliepen <guus@tinc-vpn.org>
Mon, 16 Jul 2012 14:48:24 +0000 (16:48 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Mon, 16 Jul 2012 14:48:24 +0000 (16:48 +0200)
doc/tinc.texi
doc/tincctl.8.in
src/tincctl.c

index 876fe43..fb1cd38 100644 (file)
@@ -2060,6 +2060,16 @@ If no @var{value} is given, all configuration variables with the same name will
 Start an editor for the given configuration file.
 You do not need to specify the full path to the file.
 
+@item export
+Export the host configuration file of the local node to standard output.
+
+@item export-all
+Export all host configuration files to standard output.
+
+@item import [--force]
+Import host configuration file(s) from standard input.
+Already existing host configuration files are not overwritten unless the option --force is used.
+
 @item start [tincd options]
 Start @samp{tincd}, optionally with the given extra options.
 
@@ -2153,6 +2163,7 @@ tincctl -n vpn init foo
 tincctl -n vpn config Subnet 192.168.1.0/24
 tincctl -n vpn config bar.Address bar.example.com
 tincctl -n vpn config ConnectTo bar
+tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@@example.com
 @end example
 
 @c ==================================================================
index 8693dc0..4b6d426 100644 (file)
@@ -71,6 +71,15 @@ is given, all configuration variables with the same name will be removed.
 .It edit Ar filename
 Start an editor for the given configuration file.
 You do not need to specify the full path to the file.
+.It export
+Export the host configuration file of the local node to standard output.
+.It export-all
+Export all host configuration files to standard output.
+.It import Op Fl -force
+Import host configuration file(s) from standard input.
+Already existing host configuration files are not overwritten unless the option
+.Fl -force
+is used.
 .It start Op tincd options
 Start
 .Xr tincd 8 ,
@@ -172,6 +181,7 @@ tincctl -n vpn init foo
 tincctl -n vpn config Subnet 192.168.1.0/24
 tincctl -n vpn config bar.Address bar.example.com
 tincctl -n vpn config ConnectTo bar
+tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@example.com
 .Sh TOP
 The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters.
 It displays a list of all the known nodes in the left-most column,
index f3a73b7..057ff7c 100644 (file)
@@ -56,6 +56,7 @@ static char line[4096];
 static int code;
 static int req;
 static int result;
+static bool force = false;
 
 #ifdef HAVE_MINGW
 static struct WSAData wsa_state;
@@ -75,6 +76,7 @@ static struct option const long_options[] = {
        {"chroot", no_argument, NULL, 0},
        {"user", required_argument, NULL, 0},
        {"option", required_argument, NULL, 0},
+       {"force", no_argument, NULL, 6},
        {NULL, 0, NULL, 0}
 };
 
@@ -131,6 +133,9 @@ static void usage(bool status) {
 #endif
                                "  pcap [snaplen]             Dump traffic in pcap format [up to snaplen bytes per packet]\n"
                                "  log [level]                Dump log output [up to the specified level]\n"
+                               "  export                     Export host configuration of local node to standard output\n"
+                               "  export-all                 Export all host configuration files to standard output\n"
+                               "  import [--force]           Import host configuration file(s) from standard input\n"
                                "\n");
                printf("Report bugs to tinc@tinc-vpn.org.\n");
        }
@@ -165,6 +170,10 @@ static bool parse_options(int argc, char **argv) {
                                pidfilename = xstrdup(optarg);
                                break;
 
+                       case 6:
+                               force = true;
+                               break;
+
                        case '?':
                                usage(true);
                                return false;
@@ -1363,6 +1372,131 @@ static int cmd_edit(int argc, char *argv[]) {
        return 0;
 }
 
+static int export(const char *name, FILE *out) {
+       char *filename;
+       xasprintf(&filename, "%s/%s", hosts_dir, name);
+       FILE *in = fopen(filename, "r");
+       if(!in) {
+               fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
+               return 1;
+       }
+
+       fprintf(out, "Name = %s\n", name);
+       char buf[4096];
+       while(fgets(buf, sizeof buf, in))
+               fputs(buf, out);
+
+       if(ferror(in)) {
+               fprintf(stderr, "Error while reading configuration file %s: %s\n", filename, strerror(errno));
+               return 1;
+       }
+
+       fclose(in);
+       return 0;
+}
+
+static int cmd_export(int argc, char *argv[]) {
+       char *name = get_my_name();
+       if(!name)
+               return 1;
+
+       return export(name, stdout);
+}
+
+static int cmd_export_all(int argc, char *argv[]) {
+       DIR *dir = opendir(hosts_dir);
+       if(!dir) {
+               fprintf(stderr, "Could not open host configuration directory %s: %s\n", hosts_dir, strerror(errno));
+               return 1;
+       }
+
+       bool first = true;
+       int result = 0;
+       struct dirent *ent;
+
+       while((ent = readdir(dir))) {
+               if(!check_id(ent->d_name))
+                       continue;
+
+               if(first)
+                       first = false;
+               else
+                       printf("#---------------------------------------------------------------#\n");
+
+               result |= export(ent->d_name, stdout);
+       }
+
+       closedir(dir);
+       return result;
+}
+
+static int cmd_import(int argc, char *argv[]) {
+       FILE *in = stdin;
+       FILE *out = NULL;
+
+       char buf[4096];
+       char name[4096];
+       char *filename;
+       int count = 0;
+       bool firstline = true;
+
+       while(fgets(buf, sizeof buf, in)) {
+               if(sscanf(buf, "Name = %s", name) == 1) {
+                       if(!check_id(name)) {
+                               fprintf(stderr, "Invalid Name in input!\n");
+                               return 1;
+                       }
+
+                       if(out)
+                               fclose(out);
+
+                       free(filename);
+                       xasprintf(&filename, "%s/%s", hosts_dir, name);
+
+                       if(!force && !access(filename, F_OK)) {
+                               fprintf(stderr, "Host configuration file %s already exists, skipping.\n", filename);
+                               out = NULL;
+                               continue;
+                       }
+
+                       out = fopen(filename, "w");
+                       if(!out) {
+                               fprintf(stderr, "Error creating configuration file %s: %s\n", filename, strerror(errno));
+                               return 1;
+                       }
+
+                       count++;
+                       firstline = false;
+                       continue;
+               } else if(firstline) {
+                       fprintf(stderr, "Junk at the beginning of the input, ignoring.\n");
+                       firstline = false;
+               }
+
+
+               if(!strcmp(buf, "#---------------------------------------------------------------#\n"))
+                       continue;
+
+               if(out) {
+                       if(fputs(buf, out) < 0) {
+                               fprintf(stderr, "Error writing to host configuration file %s: %s\n", filename, strerror(errno));
+                               return 1;
+                       }
+               }
+       }
+
+       if(out)
+               fclose(out);
+
+       if(count) {
+               fprintf(stderr, "Imported %d host configuration files.\n", count);
+               return 0;
+       } else {
+               fprintf(stderr, "No host configuration files imported.\n");
+               return 1;
+       }
+}
+
 static const struct {
        const char *command;
        int (*function)(int argc, char *argv[]);
@@ -1390,6 +1524,9 @@ static const struct {
        {"version", cmd_version},
        {"info", cmd_info},
        {"edit", cmd_edit},
+       {"export", cmd_export},
+       {"export-all", cmd_export_all},
+       {"import", cmd_import},
        {NULL, NULL},
 };