Have tincctl act as a shell when no command is given.
By default it uses readline to read commands. If the input and output are not a tty, no prompt is shown.
This commit is contained in:
parent
91937812bd
commit
73348be58e
4 changed files with 249 additions and 49 deletions
|
@ -182,6 +182,7 @@ dnl These are defined in files in m4/
|
||||||
AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
|
AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
|
||||||
|
|
||||||
tinc_CURSES
|
tinc_CURSES
|
||||||
|
tinc_READLINE
|
||||||
tinc_LIBEVENT
|
tinc_LIBEVENT
|
||||||
tinc_ZLIB
|
tinc_ZLIB
|
||||||
tinc_LZO
|
tinc_LZO
|
||||||
|
|
41
m4/readline.m4
Normal file
41
m4/readline.m4
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
dnl Check to find the readline headers/libraries
|
||||||
|
|
||||||
|
AC_DEFUN([tinc_READLINE],
|
||||||
|
[
|
||||||
|
AC_ARG_ENABLE([readline],
|
||||||
|
AS_HELP_STRING([--disable-readline], [disable readline support]))
|
||||||
|
AS_IF([test "x$enable_readline" != "xno"], [
|
||||||
|
AC_DEFINE(HAVE_READLINE, 1, [have readline support])
|
||||||
|
readline=true
|
||||||
|
AC_ARG_WITH(readline,
|
||||||
|
AS_HELP_STRING([--with-readline=DIR], [readline base directory, or:]),
|
||||||
|
[readline="$withval"
|
||||||
|
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
||||||
|
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
||||||
|
)
|
||||||
|
|
||||||
|
AC_ARG_WITH(readline-include,
|
||||||
|
AS_HELP_STRING([--with-readline-include=DIR], [readline headers directory]),
|
||||||
|
[readline_include="$withval"
|
||||||
|
CPPFLAGS="$CPPFLAGS -I$withval"]
|
||||||
|
)
|
||||||
|
|
||||||
|
AC_ARG_WITH(readline-lib,
|
||||||
|
AS_HELP_STRING([--with-readline-lib=DIR], [readline library directory]),
|
||||||
|
[readline_lib="$withval"
|
||||||
|
LDFLAGS="$LDFLAGS -L$withval"]
|
||||||
|
)
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS([readline/readline.h readline/history.h],
|
||||||
|
[],
|
||||||
|
[AC_MSG_ERROR("readline header files not found."); break]
|
||||||
|
)
|
||||||
|
|
||||||
|
AC_CHECK_LIB(readline, readline,
|
||||||
|
[READLINE_LIBS="-lreadline"],
|
||||||
|
[AC_MSG_ERROR("readline library not found.")]
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_SUBST(READLINE_LIBS)
|
||||||
|
])
|
|
@ -37,7 +37,7 @@ if TUNEMU
|
||||||
tincd_SOURCES += bsd/tunemu.c
|
tincd_SOURCES += bsd/tunemu.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
tincctl_LDADD = $(CURSES_LIBS)
|
tincctl_LDADD = $(CURSES_LIBS) $(READLINE_LIBS)
|
||||||
|
|
||||||
DEFAULT_INCLUDES =
|
DEFAULT_INCLUDES =
|
||||||
|
|
||||||
|
|
236
src/tincctl.c
236
src/tincctl.c
|
@ -21,6 +21,11 @@
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_READLINE
|
||||||
|
#include "readline/readline.h"
|
||||||
|
#include "readline/history.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "control_common.h"
|
#include "control_common.h"
|
||||||
|
@ -35,6 +40,7 @@
|
||||||
#define mkdir(a, b) mkdir(a)
|
#define mkdir(a, b) mkdir(a)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* The name this program was run with. */
|
/* The name this program was run with. */
|
||||||
static char *program_name = NULL;
|
static char *program_name = NULL;
|
||||||
|
|
||||||
|
@ -62,6 +68,7 @@ static int code;
|
||||||
static int req;
|
static int req;
|
||||||
static int result;
|
static int result;
|
||||||
static bool force = false;
|
static bool force = false;
|
||||||
|
static bool tty = true;
|
||||||
|
|
||||||
#ifdef HAVE_MINGW
|
#ifdef HAVE_MINGW
|
||||||
static struct WSAData wsa_state;
|
static struct WSAData wsa_state;
|
||||||
|
@ -207,14 +214,14 @@ static bool parse_options(int argc, char **argv) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FILE *ask_and_open(const char *filename, const char *what, const char *mode) {
|
static FILE *ask_and_open(const char *filename, const char *what, const char *mode, bool ask) {
|
||||||
FILE *r;
|
FILE *r;
|
||||||
char *directory;
|
char *directory;
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
char buf2[PATH_MAX];
|
char buf2[PATH_MAX];
|
||||||
|
|
||||||
/* Check stdin and stdout */
|
/* Check stdin and stdout */
|
||||||
if(isatty(0) && isatty(1)) {
|
if(ask && tty) {
|
||||||
/* Ask for a file and/or directory name. */
|
/* Ask for a file and/or directory name. */
|
||||||
fprintf(stdout, "Please enter a file to save %s to [%s]: ",
|
fprintf(stdout, "Please enter a file to save %s to [%s]: ",
|
||||||
what, filename);
|
what, filename);
|
||||||
|
@ -263,7 +270,7 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
|
||||||
Generate a public/private ECDSA keypair, and ask for a file to store
|
Generate a public/private ECDSA keypair, and ask for a file to store
|
||||||
them in.
|
them in.
|
||||||
*/
|
*/
|
||||||
static bool ecdsa_keygen() {
|
static bool ecdsa_keygen(bool ask) {
|
||||||
ecdsa_t key;
|
ecdsa_t key;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
@ -277,7 +284,7 @@ static bool ecdsa_keygen() {
|
||||||
fprintf(stderr, "Done.\n");
|
fprintf(stderr, "Done.\n");
|
||||||
|
|
||||||
xasprintf(&filename, "%s" SLASH "ecdsa_key.priv", confbase);
|
xasprintf(&filename, "%s" SLASH "ecdsa_key.priv", confbase);
|
||||||
f = ask_and_open(filename, "private ECDSA key", "a");
|
f = ask_and_open(filename, "private ECDSA key", "a", ask);
|
||||||
|
|
||||||
if(!f)
|
if(!f)
|
||||||
return false;
|
return false;
|
||||||
|
@ -300,7 +307,7 @@ static bool ecdsa_keygen() {
|
||||||
else
|
else
|
||||||
xasprintf(&filename, "%s" SLASH "ecdsa_key.pub", confbase);
|
xasprintf(&filename, "%s" SLASH "ecdsa_key.pub", confbase);
|
||||||
|
|
||||||
f = ask_and_open(filename, "public ECDSA key", "a");
|
f = ask_and_open(filename, "public ECDSA key", "a", ask);
|
||||||
|
|
||||||
if(!f)
|
if(!f)
|
||||||
return false;
|
return false;
|
||||||
|
@ -322,7 +329,7 @@ static bool ecdsa_keygen() {
|
||||||
Generate a public/private RSA keypair, and ask for a file to store
|
Generate a public/private RSA keypair, and ask for a file to store
|
||||||
them in.
|
them in.
|
||||||
*/
|
*/
|
||||||
static bool rsa_keygen(int bits) {
|
static bool rsa_keygen(int bits, bool ask) {
|
||||||
rsa_t key;
|
rsa_t key;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
@ -336,7 +343,7 @@ static bool rsa_keygen(int bits) {
|
||||||
fprintf(stderr, "Done.\n");
|
fprintf(stderr, "Done.\n");
|
||||||
|
|
||||||
xasprintf(&filename, "%s" SLASH "rsa_key.priv", confbase);
|
xasprintf(&filename, "%s" SLASH "rsa_key.priv", confbase);
|
||||||
f = ask_and_open(filename, "private RSA key", "a");
|
f = ask_and_open(filename, "private RSA key", "a", ask);
|
||||||
|
|
||||||
if(!f)
|
if(!f)
|
||||||
return false;
|
return false;
|
||||||
|
@ -359,7 +366,7 @@ static bool rsa_keygen(int bits) {
|
||||||
else
|
else
|
||||||
xasprintf(&filename, "%s" SLASH "rsa_key.pub", confbase);
|
xasprintf(&filename, "%s" SLASH "rsa_key.pub", confbase);
|
||||||
|
|
||||||
f = ask_and_open(filename, "public RSA key", "a");
|
f = ask_and_open(filename, "public RSA key", "a", ask);
|
||||||
|
|
||||||
if(!f)
|
if(!f)
|
||||||
return false;
|
return false;
|
||||||
|
@ -609,12 +616,13 @@ static bool remove_service(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool connect_tincd() {
|
static bool connect_tincd(bool verbose) {
|
||||||
if(fd >= 0)
|
if(fd >= 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
FILE *f = fopen(pidfilename, "r");
|
FILE *f = fopen(pidfilename, "r");
|
||||||
if(!f) {
|
if(!f) {
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "Could not open pid file %s: %s\n", pidfilename, strerror(errno));
|
fprintf(stderr, "Could not open pid file %s: %s\n", pidfilename, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -623,12 +631,17 @@ static bool connect_tincd() {
|
||||||
char port[128];
|
char port[128];
|
||||||
|
|
||||||
if(fscanf(f, "%20d %1024s %128s port %128s", &pid, controlcookie, host, port) != 4) {
|
if(fscanf(f, "%20d %1024s %128s port %128s", &pid, controlcookie, host, port) != 4) {
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "Could not parse pid file %s\n", pidfilename);
|
fprintf(stderr, "Could not parse pid file %s\n", pidfilename);
|
||||||
|
fclose(f);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
#ifdef HAVE_MINGW
|
#ifdef HAVE_MINGW
|
||||||
if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
|
if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
|
fprintf(stderr, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -644,12 +657,14 @@ static bool connect_tincd() {
|
||||||
struct addrinfo *res = NULL;
|
struct addrinfo *res = NULL;
|
||||||
|
|
||||||
if(getaddrinfo(host, port, &hints, &res) || !res) {
|
if(getaddrinfo(host, port, &hints, &res) || !res) {
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "Cannot resolve %s port %s: %s", host, port, strerror(errno));
|
fprintf(stderr, "Cannot resolve %s port %s: %s", host, port, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP);
|
fd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP);
|
||||||
if(fd < 0) {
|
if(fd < 0) {
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "Cannot create TCP socket: %s\n", sockstrerror(sockerrno));
|
fprintf(stderr, "Cannot create TCP socket: %s\n", sockstrerror(sockerrno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -658,11 +673,13 @@ static bool connect_tincd() {
|
||||||
unsigned long arg = 0;
|
unsigned long arg = 0;
|
||||||
|
|
||||||
if(ioctlsocket(fd, FIONBIO, &arg) != 0) {
|
if(ioctlsocket(fd, FIONBIO, &arg) != 0) {
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "ioctlsocket failed: %s", sockstrerror(sockerrno));
|
fprintf(stderr, "ioctlsocket failed: %s", sockstrerror(sockerrno));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
|
if(connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "Cannot connect to %s port %s: %s\n", host, port, sockstrerror(sockerrno));
|
fprintf(stderr, "Cannot connect to %s port %s: %s\n", host, port, sockstrerror(sockerrno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -673,6 +690,7 @@ static bool connect_tincd() {
|
||||||
int version;
|
int version;
|
||||||
|
|
||||||
if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %s %d", &code, data, &version) != 3 || code != 0) {
|
if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %s %d", &code, data, &version) != 3 || code != 0) {
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "Cannot read greeting from control socket: %s\n", sockstrerror(sockerrno));
|
fprintf(stderr, "Cannot read greeting from control socket: %s\n", sockstrerror(sockerrno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -680,6 +698,7 @@ static bool connect_tincd() {
|
||||||
sendline(fd, "%d ^%s %d", ID, controlcookie, TINC_CTL_VERSION_CURRENT);
|
sendline(fd, "%d ^%s %d", ID, controlcookie, TINC_CTL_VERSION_CURRENT);
|
||||||
|
|
||||||
if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &version, &pid) != 3 || code != 4 || version != TINC_CTL_VERSION_CURRENT) {
|
if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &version, &pid) != 3 || code != 4 || version != TINC_CTL_VERSION_CURRENT) {
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "Could not fully establish control socket connection\n");
|
fprintf(stderr, "Could not fully establish control socket connection\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -720,7 +739,7 @@ static int cmd_start(int argc, char *argv[]) {
|
||||||
|
|
||||||
static int cmd_stop(int argc, char *argv[]) {
|
static int cmd_stop(int argc, char *argv[]) {
|
||||||
#ifndef HAVE_MINGW
|
#ifndef HAVE_MINGW
|
||||||
if(!connect_tincd()) {
|
if(!connect_tincd(true)) {
|
||||||
if(pid) {
|
if(pid) {
|
||||||
if(kill(pid, SIGTERM))
|
if(kill(pid, SIGTERM))
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -749,7 +768,7 @@ static int cmd_restart(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_reload(int argc, char *argv[]) {
|
static int cmd_reload(int argc, char *argv[]) {
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
|
sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
|
||||||
|
@ -769,7 +788,7 @@ static int cmd_dump(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
bool do_graph = false;
|
bool do_graph = false;
|
||||||
|
@ -825,7 +844,7 @@ static int cmd_dump(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_purge(int argc, char *argv[]) {
|
static int cmd_purge(int argc, char *argv[]) {
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
sendline(fd, "%d %d", CONTROL, REQ_PURGE);
|
sendline(fd, "%d %d", CONTROL, REQ_PURGE);
|
||||||
|
@ -843,7 +862,7 @@ static int cmd_debug(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
int debuglevel = atoi(argv[1]);
|
int debuglevel = atoi(argv[1]);
|
||||||
|
@ -860,7 +879,7 @@ static int cmd_debug(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_retry(int argc, char *argv[]) {
|
static int cmd_retry(int argc, char *argv[]) {
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
sendline(fd, "%d %d", CONTROL, REQ_RETRY);
|
sendline(fd, "%d %d", CONTROL, REQ_RETRY);
|
||||||
|
@ -883,7 +902,7 @@ static int cmd_connect(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
sendline(fd, "%d %d %s", CONTROL, REQ_CONNECT, argv[1]);
|
sendline(fd, "%d %d %s", CONTROL, REQ_CONNECT, argv[1]);
|
||||||
|
@ -906,7 +925,7 @@ static int cmd_disconnect(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
sendline(fd, "%d %d %s", CONTROL, REQ_DISCONNECT, argv[1]);
|
sendline(fd, "%d %d %s", CONTROL, REQ_DISCONNECT, argv[1]);
|
||||||
|
@ -920,7 +939,7 @@ static int cmd_disconnect(int argc, char *argv[]) {
|
||||||
|
|
||||||
static int cmd_top(int argc, char *argv[]) {
|
static int cmd_top(int argc, char *argv[]) {
|
||||||
#ifdef HAVE_CURSES
|
#ifdef HAVE_CURSES
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
top(fd);
|
top(fd);
|
||||||
|
@ -932,7 +951,7 @@ static int cmd_top(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_pcap(int argc, char *argv[]) {
|
static int cmd_pcap(int argc, char *argv[]) {
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
pcap(fd, stdout, argc > 1 ? atoi(argv[1]) : 0);
|
pcap(fd, stdout, argc > 1 ? atoi(argv[1]) : 0);
|
||||||
|
@ -940,7 +959,7 @@ static int cmd_pcap(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_log(int argc, char *argv[]) {
|
static int cmd_log(int argc, char *argv[]) {
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
logcontrol(fd, stdout, argc > 1 ? atoi(argv[1]) : -1);
|
logcontrol(fd, stdout, argc > 1 ? atoi(argv[1]) : -1);
|
||||||
|
@ -948,7 +967,7 @@ static int cmd_log(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_pid(int argc, char *argv[]) {
|
static int cmd_pid(int argc, char *argv[]) {
|
||||||
if(!connect_tincd() && !pid)
|
if(!connect_tincd(true) && !pid)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
printf("%d\n", pid);
|
printf("%d\n", pid);
|
||||||
|
@ -1216,6 +1235,7 @@ static int cmd_config(int argc, char *argv[]) {
|
||||||
tf = fopen(tmpfile, "w");
|
tf = fopen(tmpfile, "w");
|
||||||
if(!tf) {
|
if(!tf) {
|
||||||
fprintf(stderr, "Could not open temporary file %s: %s\n", tmpfile, strerror(errno));
|
fprintf(stderr, "Could not open temporary file %s: %s\n", tmpfile, strerror(errno));
|
||||||
|
fclose(f);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1340,9 +1360,7 @@ static int cmd_config(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Silently try notifying a running tincd of changes.
|
// Silently try notifying a running tincd of changes.
|
||||||
fclose(stderr);
|
if(connect_tincd(false))
|
||||||
|
|
||||||
if(connect_tincd())
|
|
||||||
sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
|
sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1367,7 +1385,7 @@ static int cmd_init(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(argc < 2) {
|
if(argc < 2) {
|
||||||
if(isatty(0) && isatty(1)) {
|
if(tty) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
fprintf(stdout, "Enter the Name you want your tinc node to have: ");
|
fprintf(stdout, "Enter the Name you want your tinc node to have: ");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
@ -1422,8 +1440,7 @@ static int cmd_init(int argc, char *argv[]) {
|
||||||
fprintf(f, "Name = %s\n", name);
|
fprintf(f, "Name = %s\n", name);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
fclose(stdin);
|
if(!rsa_keygen(2048, false) || !ecdsa_keygen(false))
|
||||||
if(!rsa_keygen(2048) || !ecdsa_keygen())
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
#ifndef HAVE_MINGW
|
#ifndef HAVE_MINGW
|
||||||
|
@ -1446,15 +1463,15 @@ static int cmd_init(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_generate_keys(int argc, char *argv[]) {
|
static int cmd_generate_keys(int argc, char *argv[]) {
|
||||||
return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048) && ecdsa_keygen());
|
return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ecdsa_keygen(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_generate_rsa_keys(int argc, char *argv[]) {
|
static int cmd_generate_rsa_keys(int argc, char *argv[]) {
|
||||||
return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048);
|
return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_generate_ecdsa_keys(int argc, char *argv[]) {
|
static int cmd_generate_ecdsa_keys(int argc, char *argv[]) {
|
||||||
return !ecdsa_keygen();
|
return !ecdsa_keygen(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_help(int argc, char *argv[]) {
|
static int cmd_help(int argc, char *argv[]) {
|
||||||
|
@ -1473,7 +1490,7 @@ static int cmd_info(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!connect_tincd())
|
if(!connect_tincd(true))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return info(fd, argv[1]);
|
return info(fd, argv[1]);
|
||||||
|
@ -1532,9 +1549,7 @@ static int cmd_edit(int argc, char *argv[]) {
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
// Silently try notifying a running tincd of changes.
|
// Silently try notifying a running tincd of changes.
|
||||||
fclose(stderr);
|
if(connect_tincd(false))
|
||||||
|
|
||||||
if(connect_tincd())
|
|
||||||
sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
|
sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1558,6 +1573,7 @@ static int export(const char *name, FILE *out) {
|
||||||
|
|
||||||
if(ferror(in)) {
|
if(ferror(in)) {
|
||||||
fprintf(stderr, "Error while reading configuration file %s: %s\n", filename, strerror(errno));
|
fprintf(stderr, "Error while reading configuration file %s: %s\n", filename, strerror(errno));
|
||||||
|
fclose(in);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1700,6 +1716,149 @@ static const struct {
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef HAVE_READLINE
|
||||||
|
static char *complete_command(const char *text, int state) {
|
||||||
|
static int i;
|
||||||
|
|
||||||
|
if(!state)
|
||||||
|
i = 0;
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
|
||||||
|
while(commands[i].command) {
|
||||||
|
if(!strncasecmp(commands[i].command, text, strlen(text)))
|
||||||
|
return xstrdup(commands[i].command);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *complete_dump(const char *text, int state) {
|
||||||
|
const char *matches[] = {"nodes", "edges", "subnets", "connections", "graph", NULL};
|
||||||
|
static int i;
|
||||||
|
|
||||||
|
if(!state)
|
||||||
|
i = 0;
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
|
||||||
|
while(matches[i]) {
|
||||||
|
if(!strncasecmp(matches[i], text, strlen(text)))
|
||||||
|
return xstrdup(matches[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char **completion (const char *text, int start, int end) {
|
||||||
|
char **matches = NULL;
|
||||||
|
|
||||||
|
if(!start)
|
||||||
|
matches = rl_completion_matches(text, complete_command);
|
||||||
|
else if(!strncasecmp(rl_line_buffer, "dump ", 5))
|
||||||
|
matches = rl_completion_matches(text, complete_dump);
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int cmd_shell(int argc, char *argv[]) {
|
||||||
|
char *prompt;
|
||||||
|
xasprintf(&prompt, "%s> ", identname);
|
||||||
|
int result = 0;
|
||||||
|
char buf[4096];
|
||||||
|
char *line = NULL;
|
||||||
|
int maxargs = argc + 16;
|
||||||
|
char **nargv = xmalloc(maxargs * sizeof *nargv);
|
||||||
|
optind = argc;
|
||||||
|
|
||||||
|
for(int i = 0; i < argc; i++)
|
||||||
|
nargv[i] = argv[i];
|
||||||
|
|
||||||
|
#ifdef HAVE_READLINE
|
||||||
|
rl_readline_name = "tinc";
|
||||||
|
rl_attempted_completion_function = completion;
|
||||||
|
rl_filename_completion_desired = 0;
|
||||||
|
char *copy = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
#ifdef HAVE_READLINE
|
||||||
|
if(tty) {
|
||||||
|
free(copy);
|
||||||
|
free(line);
|
||||||
|
line = readline(prompt);
|
||||||
|
if(line)
|
||||||
|
copy = xstrdup(line);
|
||||||
|
} else {
|
||||||
|
line = fgets(buf, sizeof buf, stdin);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if(tty)
|
||||||
|
fputs(stdout, prompt);
|
||||||
|
|
||||||
|
line = fgets(buf, sizeof buf, stdin);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(!line)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Ignore comments */
|
||||||
|
|
||||||
|
if(*line == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Split */
|
||||||
|
|
||||||
|
int nargc = argc;
|
||||||
|
char *p = line + strspn(line, " \t\n");
|
||||||
|
char *next = strtok(p, " \t\n");
|
||||||
|
|
||||||
|
while(p && *p) {
|
||||||
|
if(nargc >= maxargs) {
|
||||||
|
fprintf(stderr, "next %p '%s', p %p '%s'\n", next, next, p, p);
|
||||||
|
abort();
|
||||||
|
maxargs *= 2;
|
||||||
|
nargv = xrealloc(nargv, maxargs * sizeof *nargv);
|
||||||
|
}
|
||||||
|
|
||||||
|
nargv[nargc++] = p;
|
||||||
|
p = next;
|
||||||
|
next = strtok(NULL, " \t\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nargc == argc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for(int i = 0; commands[i].command; i++) {
|
||||||
|
if(!strcasecmp(nargv[argc], commands[i].command)) {
|
||||||
|
result |= commands[i].function(nargc - argc - 1, nargv + argc + 1);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_READLINE
|
||||||
|
if(found)
|
||||||
|
add_history(copy);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(!found) {
|
||||||
|
fprintf(stderr, "Unknown command `%s'.\n", nargv[argc]);
|
||||||
|
result |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tty)
|
||||||
|
printf("\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
program_name = argv[0];
|
program_name = argv[0];
|
||||||
|
|
||||||
|
@ -1718,11 +1877,10 @@ int main(int argc, char *argv[]) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(optind >= argc) {
|
tty = isatty(0) && isatty(1);
|
||||||
fprintf(stderr, "No command given.\n");
|
|
||||||
usage(true);
|
if(optind >= argc)
|
||||||
return 1;
|
return cmd_shell(argc, argv);
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; commands[i].command; i++) {
|
for(int i = 0; commands[i].command; i++) {
|
||||||
if(!strcasecmp(argv[optind], commands[i].command))
|
if(!strcasecmp(argv[optind], commands[i].command))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue