prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="-c -d -D -K -n -o -L -R -U --config --no-detach --debug --net --option --mlock --logfile --pidfile --chroot --user --help --version"
confvars="Address AddressFamily BindToAddress BindToInterface Broadcast Cipher ClampMSS Compression ConnectTo DecrementTTL Device DeviceType Digest DirectOnly ECDSAPrivateKeyFile ECDSAPublicKey ECDSAPublicKeyFile ExperimentalProtocol Forwarding GraphDumpFile Hostnames IffOneQueue IndirectData Interface KeyExpire ListenAddress LocalDiscovery MACExpire MACLength MaxOutputBufferSize MaxTimeout Mode Name PMTU PMTUDiscovery PingInterval PingTimeout Port PriorityInheritance PrivateKeyFile ProcessPriority Proxy PublicKeyFile ReplayWindow StrictSubnets Subnet TCPOnly TunnelServer UDPRcvBuf UDPSndBuf VDEGroup VDEPort Weight"
- commands="add connect debug del disconnect dump edit export export-all generate-ecdsa-keys generate-keys generate-rsa-keys get help import info init invite join log pcap pid purge reload restart retry set start stop top version"
+ commands="add connect debug del disconnect dump edit export export-all generate-ecdsa-keys generate-keys generate-rsa-keys get help import info init invite join log network pcap pid purge reload restart retry set start stop top version"
case ${prev} in
-c|--config)
COMPREPLY=( $(compgen -W "reachable nodes edges subnets connections graph" -- ${cur}) )
return 0
;;
+ network)
+ nets=""
+ pushd /etc/tinc >/dev/null 2>/dev/null
+ for dir in *; do
+ if [[ -f "$dir/tinc.conf" ]]; then
+ nets="$nets $dir"
+ fi
+ done
+ popd >/dev/null 2>/dev/null
+ COMPREPLY=( $(compgen -W "${nets}" -- ${cur}) )
+ return 0
+ ;;
esac
if [[ -z ${cur} ]] ; then
COMPREPLY=( $(compgen -W "${opts} ${commands}" -- ${cur}) )
bool netnamegiven = false;
char *scriptinterpreter = NULL;
char *scriptextension = "";
+static char *prompt;
static struct option const long_options[] = {
{"config", required_argument, NULL, 'c'},
" 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");
}
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[]);
{"exchange-all", cmd_exchange_all},
{"invite", cmd_invite},
{"join", cmd_join},
+ {"network", cmd_network},
{NULL, NULL},
};
#endif
static int cmd_shell(int argc, char *argv[]) {
- char *prompt;
xasprintf(&prompt, "%s> ", identname);
int result = 0;
char buf[4096];