Here are the tincctl patches I've been working on. They apply to
http://www.tinc-vpn.org/svn/tinc/branches/1.1@1545. I intend to commit
them once the crypto stuff's fixed. Since they're basically done,
I'm
emailing them now for review and in case I lose my hard drive or something.
They implement a pretty full set of tincctl operations. A few notes:
* I removed most of the weirder signal handlers - didn't see much use
for them once this was added.
* I put in a binary protocol for sending request/responses. Maybe
overkill, but I wanted something that would convey error status and
message boundaries.
* I also removed the GraphDumpFile configuration option. I think now it
makes more sense to do this sort of thing with a cron job based on
"tincctl -n NET dump graph".
Best regards,
Scott
--
Scott Lamb <http://www.slamb.org/>
-------------- next part -------------->From edfdd938ae878ad3f6a0b5942b1493189e29bf22 Mon Sep 17 00:00:00 2001
From: Scott Lamb <slamb@slamb.org>
Date: Sat, 21 Jul 2007 12:20:54 -0700
Subject: [PATCH] Dump through control socket
Note this removes SIGUSR1, SIGUSR2, and the graph dumping config option.
It seems cleaner to do everything through the control socket.
---
doc/tinc.conf.5.in | 12 ----------
doc/tinc.texi | 16 --------------
doc/tincctl.8.in | 2 +-
doc/tincd.8.in | 4 ---
src/connection.c | 13 ++++++-----
src/connection.h | 2 +-
src/control.c | 32 ++++++++++++++++++++++++++++-
src/control_common.h | 5 ++++
src/edge.c | 15 ++++++++-----
src/edge.h | 2 +-
src/graph.c | 55 +++++++++++--------------------------------------
src/graph.h | 2 +-
src/net.c | 21 -------------------
src/node.c | 11 ++++-----
src/node.h | 2 +-
src/subnet.c | 10 ++++----
src/subnet.h | 2 +-
src/tincctl.c | 28 +++++++++++++++++++++++++
18 files changed, 109 insertions(+), 125 deletions(-)
diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in
index 978bdc1..83d2541 100644
--- a/doc/tinc.conf.5.in
+++ b/doc/tinc.conf.5.in
@@ -147,18 +147,6 @@ instead of
.Va Device .
The info pages of the tinc package contain more information
about configuring the virtual network device.
-.It Va GraphDumpFile Li = Ar filename Bq experimental
-If this option is present,
-.Nm tinc
-will dump the current network graph to the file
-.Ar filename
-every minute, unless there were no changes to the graph.
-The file is in a format that can be read by graphviz tools.
-If
-.Ar filename
-starts with a pipe symbol |,
-then the rest of the filename is interpreted as a shell command
-that is executed, the graph is then sent to stdin.
.It Va Hostnames Li = yes | no Pq no
This option selects whether IP addresses (both real and on the VPN) should
be resolved. Since DNS lookups are blocking, it might affect tinc's
diff --git a/doc/tinc.texi b/doc/tinc.texi
index 2ea54be..541d2de 100644
--- a/doc/tinc.texi
+++ b/doc/tinc.texi
@@ -885,16 +885,6 @@ Under Windows, use @var{Interface} instead of @var{Device}.
Note that you can only use one device per daemon.
See also @ref{Device files}.
-@cindex GraphDumpFile
-@item GraphDumpFile = <@var{filename}> [experimental]
-If this option is present,
-tinc will dump the current network graph to the file @var{filename}
-every minute, unless there were no changes to the graph.
-The file is in a format that can be read by graphviz tools.
-If @var{filename} starts with a pipe symbol |,
-then the rest of the filename is interpreted as a shell command
-that is executed, the graph is then sent to stdin.
-
@cindex Hostnames
@item Hostnames = <yes|no> (no)
This option selects whether IP addresses (both real and on the VPN)
@@ -1579,12 +1569,6 @@ New outgoing connections specified in @file{tinc.conf}
will be made.
Temporarily increases debug level to 5.
Send this signal again to revert to the original level.
-@item USR1
-Dumps the connection list to syslog.
-
-@item USR2
-Dumps virtual network device statistics, all known nodes, edges and subnets to
syslog.
-
@item WINCH
Purges all information remembered about unreachable nodes.
diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in
index eeb5031..734bb4f 100644
--- a/doc/tincctl.8.in
+++ b/doc/tincctl.8.in
@@ -78,7 +78,7 @@ Dump a graph of the VPN in
format.
.El
.Sh BUGS
-The "start", "restart", "reload", and
"dump" commands are not yet implemented.
+The "start", "restart", and "reload" commands are
not yet implemented.
.Pp
If you find any bugs, report them to tinc@tinc-vpn.org.
.Sh SEE ALSO
diff --git a/doc/tincd.8.in b/doc/tincd.8.in
index 37a134e..f136a1b 100644
--- a/doc/tincd.8.in
+++ b/doc/tincd.8.in
@@ -98,10 +98,6 @@ will be made.
.It INT
Temporarily increases debug level to 5.
Send this signal again to revert to the original level.
-.It USR1
-Dumps the connection list to syslog.
-.It USR2
-Dumps virtual network device statistics, all known nodes, edges and subnets to
syslog.
.It WINCH
Purges all information remembered about unreachable nodes.
.El
diff --git a/src/connection.c b/src/connection.c
index 21cb6aa..06f51b5 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -106,21 +106,22 @@ void connection_del(connection_t *c) {
splay_delete(connection_tree, c);
}
-void dump_connections(void) {
+int dump_connections(struct evbuffer *out) {
splay_node_t *node;
connection_t *c;
cp();
- logger(LOG_DEBUG, _("Connections:"));
-
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
- logger(LOG_DEBUG, _(" %s at %s options %lx socket %d status %04x"),
- c->name, c->hostname, c->options, c->socket,
c->status.value);
+ if(evbuffer_add_printf(out,
+ _(" %s at %s options %lx socket %d status %04x\n"),
+ c->name, c->hostname, c->options, c->socket,
+ c->status.value) == -1)
+ return errno;
}
- logger(LOG_DEBUG, _("End of connections."));
+ return 0;
}
bool read_connection_config(connection_t *c) {
diff --git a/src/connection.h b/src/connection.h
index 2426a22..ddff03b 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -109,7 +109,7 @@ extern connection_t *new_connection(void) __attribute__
((__malloc__));
extern void free_connection(connection_t *);
extern void connection_add(connection_t *);
extern void connection_del(connection_t *);
-extern void dump_connections(void);
+extern int dump_connections(struct evbuffer *);
extern bool read_connection_config(connection_t *);
#endif /* __TINC_CONNECTION_H__ */
diff --git a/src/control.c b/src/control.c
index e2d3d3a..2009c22 100644
--- a/src/control.c
+++ b/src/control.c
@@ -60,11 +60,41 @@ static void handle_control_data(struct bufferevent *event,
void *data) {
}
if(req->type == REQ_STOP) {
- logger(LOG_NOTICE, _("Got stop command"));
+ logger(LOG_NOTICE, _("Got '%s' command"),
"stop");
event_loopexit(NULL);
goto respond;
}
+ if(req->type == REQ_DUMP_NODES) {
+ logger(LOG_NOTICE, _("Got '%s' command"), "dump
nodes");
+ res.res_errno = dump_nodes(res_data);
+ goto respond;
+ }
+
+ if(req->type == REQ_DUMP_EDGES) {
+ logger(LOG_NOTICE, _("Got '%s' command"), "dump
edges");
+ res.res_errno = dump_edges(res_data);
+ goto respond;
+ }
+
+ if(req->type == REQ_DUMP_SUBNETS) {
+ logger(LOG_NOTICE, _("Got '%s' command"), "dump
subnets");
+ res.res_errno = dump_subnets(res_data);
+ goto respond;
+ }
+
+ if(req->type == REQ_DUMP_CONNECTIONS) {
+ logger(LOG_NOTICE, _("Got '%s' command"), "dump
connections");
+ res.res_errno = dump_connections(res_data);
+ goto respond;
+ }
+
+ if(req->type == REQ_DUMP_GRAPH) {
+ logger(LOG_NOTICE, _("Got '%s' command"), "dump
graph");
+ res.res_errno = dump_graph(res_data);
+ goto respond;
+ }
+
logger(LOG_DEBUG, _("Malformed control command received"));
res.res_errno = EINVAL;
diff --git a/src/control_common.h b/src/control_common.h
index 87b893f..2ac208c 100644
--- a/src/control_common.h
+++ b/src/control_common.h
@@ -26,6 +26,11 @@ enum request_type {
REQ_STOP,
REQ_RELOAD,
REQ_RESTART,
+ REQ_DUMP_NODES,
+ REQ_DUMP_EDGES,
+ REQ_DUMP_SUBNETS,
+ REQ_DUMP_CONNECTIONS,
+ REQ_DUMP_GRAPH,
};
#define TINC_CTL_VERSION_CURRENT 0
diff --git a/src/edge.c b/src/edge.c
index 861b945..3b584f3 100644
--- a/src/edge.c
+++ b/src/edge.c
@@ -125,7 +125,7 @@ edge_t *lookup_edge(node_t *from, node_t *to) {
return splay_search(from->edge_tree, &v);
}
-void dump_edges(void) {
+int dump_edges(struct evbuffer *out) {
splay_node_t *node, *node2;
node_t *n;
edge_t *e;
@@ -133,18 +133,21 @@ void dump_edges(void) {
cp();
- logger(LOG_DEBUG, _("Edges:"));
-
for(node = node_tree->head; node; node = node->next) {
n = node->data;
for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
e = node2->data;
address = sockaddr2hostname(&e->address);
- logger(LOG_DEBUG, _(" %s to %s at %s options %lx weight %d"),
- e->from->name, e->to->name, address, e->options,
e->weight);
+ if(evbuffer_add_printf(out,
+ _(" %s to %s at %s options %lx weight %d\n"),
+ e->from->name, e->to->name, address,
+ e->options, e->weight) == -1) {
+ free(address);
+ return errno;
+ }
free(address);
}
}
- logger(LOG_DEBUG, _("End of edges."));
+ return 0;
}
diff --git a/src/edge.h b/src/edge.h
index 082ea5d..dd3d670 100644
--- a/src/edge.h
+++ b/src/edge.h
@@ -51,6 +51,6 @@ extern void free_edge_tree(splay_tree_t *);
extern void edge_add(edge_t *);
extern void edge_del(edge_t *);
extern edge_t *lookup_edge(struct node_t *, struct node_t *);
-extern void dump_edges(void);
+extern int dump_edges(struct evbuffer *);
#endif /* __TINC_EDGE_H__ */
diff --git a/src/graph.c b/src/graph.c
index 5bf6361..e6d70af 100644
--- a/src/graph.c
+++ b/src/graph.c
@@ -313,66 +313,37 @@ void sssp_bfs(void) {
dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true
*/
-static void dump_graph(int fd, short events, void *data) {
+int dump_graph(struct evbuffer *out) {
splay_node_t *node;
node_t *n;
edge_t *e;
- char *filename = NULL, *tmpname = NULL;
- FILE *file;
-
- if(!get_config_string(lookup_config(config_tree, "GraphDumpFile"),
&filename))
- return;
- ifdebug(PROTOCOL) logger(LOG_NOTICE, "Dumping graph");
-
- if(filename[0] == '|') {
- file = popen(filename + 1, "w");
- } else {
- asprintf(&tmpname, "%s.new", filename);
- file = fopen(tmpname, "w");
- }
-
- if(!file) {
- logger(LOG_ERR, "Unable to open graph dump file %s: %s", filename,
strerror(errno));
- free(tmpname);
- return;
- }
-
- fprintf(file, "digraph {\n");
+ if(evbuffer_add_printf(out, "digraph {\n") == -1)
+ return errno;
/* dump all nodes first */
for(node = node_tree->head; node; node = node->next) {
n = node->data;
- fprintf(file, " %s [label = \"%s\"];\n", n->name,
n->name);
+ if(evbuffer_add_printf(out, " %s [label = \"%s\"];\n",
+ n->name, n->name) == -1)
+ return errno;
}
/* now dump all edges */
for(node = edge_weight_tree->head; node; node = node->next) {
e = node->data;
- fprintf(file, " %s -> %s;\n", e->from->name,
e->to->name);
+ if(evbuffer_add_printf(out, " %s -> %s;\n",
+ e->from->name, e->to->name) == -1)
+ return errno;
}
- fprintf(file, "}\n");
-
- if(filename[0] == '|') {
- pclose(file);
- } else {
- fclose(file);
-#ifdef HAVE_MINGW
- unlink(filename);
-#endif
- rename(tmpname, filename);
- free(tmpname);
- }
+ if(evbuffer_add_printf(out, "}\n") == -1)
+ return errno;
+
+ return 0;
}
void graph(void) {
- static struct event ev;
-
sssp_bfs();
mst_kruskal();
-
- if(!timeout_initialized(&ev))
- timeout_set(&ev, dump_graph, NULL);
- event_add(&ev, &(struct timeval){5, 0});
}
diff --git a/src/graph.h b/src/graph.h
index 0d5be20..88de9f6 100644
--- a/src/graph.h
+++ b/src/graph.h
@@ -26,6 +26,6 @@
extern void graph(void);
extern void mst_kruskal(void);
extern void sssp_bfs(void);
-extern void dump_graph(void);
+extern int dump_graph(struct evbuffer *);
#endif /* __TINC_GRAPH_H__ */
diff --git a/src/net.c b/src/net.c
index 1b5bb16..3b180ff 100644
--- a/src/net.c
+++ b/src/net.c
@@ -252,19 +252,6 @@ static void sigint_handler(int signal, short events, void
*data) {
}
}
-static void sigusr1_handler(int signal, short events, void *data) {
- logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
- dump_connections();
-}
-
-static void sigusr2_handler(int signal, short events, void *data) {
- logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
- dump_device_stats();
- dump_nodes();
- dump_edges();
- dump_subnets();
-}
-
static void sigwinch_handler(int signal, short events, void *data) {
logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
purge();
@@ -345,8 +332,6 @@ int main_loop(void) {
struct event sigint_event;
struct event sigterm_event;
struct event sigquit_event;
- struct event sigusr1_event;
- struct event sigusr2_event;
struct event sigwinch_event;
struct event sigalrm_event;
@@ -362,10 +347,6 @@ int main_loop(void) {
signal_add(&sigterm_event, NULL);
signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL);
signal_add(&sigquit_event, NULL);
- signal_set(&sigusr1_event, SIGUSR1, sigusr1_handler, NULL);
- signal_add(&sigusr1_event, NULL);
- signal_set(&sigusr2_event, SIGUSR2, sigusr2_handler, NULL);
- signal_add(&sigusr2_event, NULL);
signal_set(&sigwinch_event, SIGWINCH, sigwinch_handler, NULL);
signal_add(&sigwinch_event, NULL);
signal_set(&sigalrm_event, SIGALRM, sigalrm_handler, NULL);
@@ -380,8 +361,6 @@ int main_loop(void) {
signal_del(&sigint_event);
signal_del(&sigterm_event);
signal_del(&sigquit_event);
- signal_del(&sigusr1_event);
- signal_del(&sigusr2_event);
signal_del(&sigwinch_event);
signal_del(&sigalrm_event);
event_del(&timeout_event);
diff --git a/src/node.c b/src/node.c
index cbafe71..0960ca7 100644
--- a/src/node.c
+++ b/src/node.c
@@ -160,22 +160,21 @@ node_t *lookup_node_udp(const sockaddr_t *sa) {
return splay_search(node_udp_tree, &n);
}
-void dump_nodes(void) {
+int dump_nodes(struct evbuffer *out) {
splay_node_t *node;
node_t *n;
cp();
- logger(LOG_DEBUG, _("Nodes:"));
-
for(node = node_tree->head; node; node = node->next) {
n = node->data;
- logger(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d
compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max
%d)"),
+ if(evbuffer_add_printf(out, _(" %s at %s cipher %d digest %d maclength
%d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max
%d)\n"),
n->name, n->hostname, n->cipher ? n->cipher->nid : 0,
n->digest ? n->digest->type : 0, n->maclength,
n->compression,
n->options, *(uint32_t *)&n->status, n->nexthop ?
n->nexthop->name : "-",
- n->via ? n->via->name : "-", n->mtu, n->minmtu,
n->maxmtu);
+ n->via ? n->via->name : "-", n->mtu, n->minmtu,
n->maxmtu) == -1)
+ return errno;
}
- logger(LOG_DEBUG, _("End of nodes."));
+ return 0;
}
diff --git a/src/node.h b/src/node.h
index 83af5e3..0476cdb 100644
--- a/src/node.h
+++ b/src/node.h
@@ -94,6 +94,6 @@ extern void node_add(node_t *);
extern void node_del(node_t *);
extern node_t *lookup_node(char *);
extern node_t *lookup_node_udp(const sockaddr_t *);
-extern void dump_nodes(void);
+extern int dump_nodes(struct evbuffer *);
#endif /* __TINC_NODE_H__ */
diff --git a/src/subnet.c b/src/subnet.c
index bbf4edd..bc92e18 100644
--- a/src/subnet.c
+++ b/src/subnet.c
@@ -438,7 +438,7 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up)
{
}
}
-void dump_subnets(void)
+int dump_subnets(struct evbuffer *out)
{
char netstr[MAXNETSTR];
subnet_t *subnet;
@@ -446,14 +446,14 @@ void dump_subnets(void)
cp();
- logger(LOG_DEBUG, _("Subnet list:"));
-
for(node = subnet_tree->head; node; node = node->next) {
subnet = node->data;
if(!net2str(netstr, sizeof netstr, subnet))
continue;
- logger(LOG_DEBUG, _(" %s owner %s"), netstr,
subnet->owner->name);
+ if(evbuffer_add_printf(out, _(" %s owner %s"),
+ netstr, subnet->owner->name) == -1)
+ return errno;
}
- logger(LOG_DEBUG, _("End of subnet list."));
+ return 0;
}
diff --git a/src/subnet.h b/src/subnet.h
index f73aaf9..48eec52 100644
--- a/src/subnet.h
+++ b/src/subnet.h
@@ -81,6 +81,6 @@ extern subnet_t *lookup_subnet(const struct node_t *, const
subnet_t *);
extern subnet_t *lookup_subnet_mac(const mac_t *);
extern subnet_t *lookup_subnet_ipv4(const ipv4_t *);
extern subnet_t *lookup_subnet_ipv6(const ipv6_t *);
-extern void dump_subnets(void);
+extern int dump_subnets(struct evbuffer *);
#endif /* __TINC_SUBNET_H__ */
diff --git a/src/tincctl.c b/src/tincctl.c
index 8a9c883..2e404d0 100644
--- a/src/tincctl.c
+++ b/src/tincctl.c
@@ -538,6 +538,34 @@ int main(int argc, char *argv[], char *envp[]) {
return send_ctl_request_cooked(fd, REQ_RESTART, NULL, 0) != -1;
}
+ if(!strcasecmp(argv[optind], "dump")) {
+ if (argc < optind + 2) {
+ fprintf(stderr, _("Not enough arguments.\n"));
+ usage(true);
+ return 1;
+ }
+
+ if(!strcasecmp(argv[optind+1], "nodes")) {
+ return send_ctl_request_cooked(fd, REQ_DUMP_NODES, NULL, 0) != -1;
+ }
+
+ if(!strcasecmp(argv[optind+1], "edges")) {
+ return send_ctl_request_cooked(fd, REQ_DUMP_EDGES, NULL, 0) != -1;
+ }
+
+ if(!strcasecmp(argv[optind+1], "subnets")) {
+ return send_ctl_request_cooked(fd, REQ_DUMP_SUBNETS, NULL, 0) != -1;
+ }
+
+ if(!strcasecmp(argv[optind+1], "connections")) {
+ return send_ctl_request_cooked(fd, REQ_DUMP_CONNECTIONS, NULL, 0) != -1;
+ }
+
+ if(!strcasecmp(argv[optind+1], "graph")) {
+ return send_ctl_request_cooked(fd, REQ_DUMP_GRAPH, NULL, 0) != -1;
+ }
+ }
+
fprintf(stderr, _("Unknown command `%s'.\n"), argv[optind]);
usage(true);
--
1.5.2.2.238.g7cbf2f2-dirty
-------------- next part -------------->From 5f817642ddaff916cc93aba26cf7bdd089168177 Mon Sep 17 00:00:00 2001
From: Scott Lamb <slamb@slamb.org>
Date: Sat, 21 Jul 2007 12:20:54 -0700
Subject: [PATCH] Avoid Linux-only credential-based pid passing
In particular, *BSD's closest equivalent (LOCAL_PEERCRED / struct xucred)
does not support pids.
---
src/control.c | 1 +
src/control_common.h | 1 +
src/tincctl.c | 10 +---------
3 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/src/control.c b/src/control.c
index d74f7e4..e2d3d3a 100644
--- a/src/control.c
+++ b/src/control.c
@@ -120,6 +120,7 @@ static void handle_new_control_socket(int fd, short events,
void *data) {
memset(&greeting, 0, sizeof greeting);
greeting.version = TINC_CTL_VERSION_CURRENT;
+ greeting.pid = getpid();
if(bufferevent_write(ev, &greeting, sizeof greeting) == -1) {
logger(LOG_ERR,
_("Cannot send greeting for new control connection: %s"),
diff --git a/src/control_common.h b/src/control_common.h
index 3fa034e..87b893f 100644
--- a/src/control_common.h
+++ b/src/control_common.h
@@ -33,6 +33,7 @@ enum request_type {
/* This greeting is sent by the server on socket open. */
typedef struct tinc_ctl_greeting_t {
int version;
+ pid_t pid;
} tinc_ctl_greeting_t;
/* A single request or response header. */
diff --git a/src/tincctl.c b/src/tincctl.c
index 3944fa2..8a9c883 100644
--- a/src/tincctl.c
+++ b/src/tincctl.c
@@ -521,16 +521,8 @@ int main(int argc, char *argv[], char *envp[]) {
return 1;
}
- struct ucred cred;
- socklen_t credlen = sizeof cred;
-
- if(getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &credlen) < 0) {
- fprintf(stderr, _("Could not obtain PID: %s\n"), strerror(errno));
- return 1;
- }
-
if(!strcasecmp(argv[optind], "pid")) {
- printf("%d\n", cred.pid);
+ printf("%d\n", greeting.pid);
return 0;
}
--
1.5.2.2.238.g7cbf2f2-dirty
-------------- next part -------------->From 44a6cef28c3337992d8d3badfbb032264e3b7ef4 Mon Sep 17 00:00:00 2001
From: Scott Lamb <slamb@slamb.org>
Date: Sat, 21 Jul 2007 12:20:22 -0700
Subject: [PATCH] Fancier protocol for control socket
* pass error status back
* pass message boundaries
---
src/control.c | 62 +++++++++++++++++++++--
src/control_common.h | 46 +++++++++++++++++
src/tincctl.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 230 insertions(+), 13 deletions(-)
create mode 100644 src/control_common.h
diff --git a/src/control.c b/src/control.c
index b3cce92..d74f7e4 100644
--- a/src/control.c
+++ b/src/control.c
@@ -24,6 +24,7 @@
#include "system.h"
#include "conf.h"
#include "control.h"
+#include "control_common.h"
#include "logger.h"
#include "xalloc.h"
@@ -33,17 +34,56 @@ static splay_tree_t *control_socket_tree;
extern char *controlsocketname;
static void handle_control_data(struct bufferevent *event, void *data) {
- char *line = evbuffer_readline(event->input);
- if(!line)
+ tinc_ctl_request_t *req;
+ size_t size;
+ tinc_ctl_request_t res;
+ struct evbuffer *res_data = NULL;
+
+ if(EVBUFFER_LENGTH(event->input) < sizeof(tinc_ctl_request_t))
return;
-
- if(!strcasecmp(line, "stop")) {
+
+ req = (tinc_ctl_request_t*) EVBUFFER_DATA(event->input);
+ if(EVBUFFER_LENGTH(event->input) < req->length)
+ return;
+
+ if(req->length < sizeof(tinc_ctl_request_t))
+ goto failure;
+
+ memset(&res, 0, sizeof res);
+ res.type = req->type;
+ res.id = req->id;
+
+ res_data = evbuffer_new();
+ if (res_data == NULL) {
+ res.res_errno = ENOMEM;
+ goto respond;
+ }
+
+ if(req->type == REQ_STOP) {
logger(LOG_NOTICE, _("Got stop command"));
event_loopexit(NULL);
- return;
+ goto respond;
}
logger(LOG_DEBUG, _("Malformed control command received"));
+ res.res_errno = EINVAL;
+
+respond:
+ res.length = (sizeof res)
+ + ((res_data == NULL) ? 0 : EVBUFFER_LENGTH(res_data));
+ evbuffer_drain(event->input, req->length);
+ if(bufferevent_write(event, &res, sizeof res) == -1)
+ goto failure;
+ if(res_data != NULL) {
+ if(bufferevent_write_buffer(event, res_data) == -1)
+ goto failure;
+ evbuffer_free(res_data);
+ }
+ return;
+
+failure:
+ logger(LOG_INFO, _("Closing control socket on error"));
+ evbuffer_free(res_data);
close(event->ev_read.ev_fd);
splay_delete(control_socket_tree, event);
}
@@ -61,6 +101,7 @@ static void handle_control_error(struct bufferevent *event,
short what, void *da
static void handle_new_control_socket(int fd, short events, void *data) {
int newfd;
struct bufferevent *ev;
+ tinc_ctl_greeting_t greeting;
newfd = accept(fd, NULL, NULL);
@@ -77,6 +118,17 @@ static void handle_new_control_socket(int fd, short events,
void *data) {
return;
}
+ memset(&greeting, 0, sizeof greeting);
+ greeting.version = TINC_CTL_VERSION_CURRENT;
+ if(bufferevent_write(ev, &greeting, sizeof greeting) == -1) {
+ logger(LOG_ERR,
+ _("Cannot send greeting for new control connection: %s"),
+ strerror(errno));
+ bufferevent_free(ev);
+ close(newfd);
+ return;
+ }
+
bufferevent_enable(ev, EV_READ);
splay_insert(control_socket_tree, ev);
diff --git a/src/control_common.h b/src/control_common.h
new file mode 100644
index 0000000..3fa034e
--- /dev/null
+++ b/src/control_common.h
@@ -0,0 +1,46 @@
+/*
+ control_protocol.h -- control socket protocol.
+ Copyright (C) 2007 Scott Lamb <slamb@slamb.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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __TINC_CONTROL_PROTOCOL_H__
+#define __TINC_CONTROL_PROTOCOL_H__
+
+enum request_type {
+ REQ_STOP,
+ REQ_RELOAD,
+ REQ_RESTART,
+};
+
+#define TINC_CTL_VERSION_CURRENT 0
+
+/* This greeting is sent by the server on socket open. */
+typedef struct tinc_ctl_greeting_t {
+ int version;
+} tinc_ctl_greeting_t;
+
+/* A single request or response header. */
+typedef struct tinc_ctl_request_t {
+ size_t length; /* total length, including the header */
+ enum request_type type;
+ int id;
+ int res_errno; /* used only for responses */
+} tinc_ctl_request_t;
+
+#endif
diff --git a/src/tincctl.c b/src/tincctl.c
index 5d65f3a..3944fa2 100644
--- a/src/tincctl.c
+++ b/src/tincctl.c
@@ -30,8 +30,9 @@
#include <getopt.h>
-#include "protocol.h"
#include "xalloc.h"
+#include "protocol.h"
+#include "control_common.h"
/* The name this program was run with. */
char *program_name = NULL;
@@ -327,9 +328,118 @@ static void make_names(void) {
}
}
+static int fullread(int fd, void *data, size_t datalen) {
+ int rv, len = 0;
+
+ while (len < datalen) {
+ rv = read(fd, data + len, datalen - len);
+ if(rv == -1 && errno == EINTR)
+ continue;
+ else if (rv == -1)
+ return rv;
+ else if (rv == 0) {
+ errno = ENODATA;
+ return -1;
+ }
+ len += rv;
+ }
+ return 0;
+}
+
+/*
+ Send a request (raw)
+*/
+static int send_ctl_request(int fd, enum request_type type,
+ void const *outdata, size_t outdatalen,
+ int *res_errno_p, void **indata_p,
+ size_t *indatalen_p) {
+ tinc_ctl_request_t req;
+ int rv;
+ struct iovec vector[2] = {
+ {&req, sizeof(req)},
+ {(void*) outdata, outdatalen}
+ };
+ void *indata;
+
+ if(res_errno_p == NULL)
+ return -1;
+
+ memset(&req, 0, sizeof req);
+ req.length = sizeof req + outdatalen;
+ req.type = type;
+ req.res_errno = 0;
+
+ while((rv = writev(fd, vector, 2)) == -1 && errno == EINTR) ;
+ if(rv != req.length)
+ return -1;
+
+ if(fullread(fd, &req, sizeof req) == -1)
+ return -1;
+
+ if(req.length < sizeof req) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(req.length > sizeof req) {
+ if (indata_p == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ indata = xmalloc(req.length - sizeof req);
+
+ if(fullread(fd, indata, req.length - sizeof req) == -1) {
+ free(indata);
+ return -1;
+ }
+
+ *indata_p = indata;
+ if(indatalen_p != NULL)
+ *indatalen_p = req.length - sizeof req;
+ }
+
+ *res_errno_p = req.res_errno;
+
+ return 0;
+}
+
+/*
+ Send a request (with printfs)
+*/
+static int send_ctl_request_cooked(int fd, enum request_type type,
+ void const *outdata, size_t outdatalen)
+{
+ int res_errno = -1;
+ char *buf = NULL;
+ size_t buflen = 0;
+
+ if(send_ctl_request(fd, type, outdata, outdatalen, &res_errno,
+ (void**) &buf, &buflen)) {
+ fprintf(stderr, _("Error sending request: %s\n"), strerror(errno));
+ return -1;
+ }
+
+ if(buf != NULL) {
+ printf("%*s", buflen, buf);
+ free(buf);
+ }
+
+ if(res_errno != 0) {
+ fprintf(stderr, _("Server reported error: %s\n"),
strerror(res_errno));
+ return -1;
+ }
+
+ return 0;
+}
+
int main(int argc, char *argv[], char *envp[]) {
- int fd;
struct sockaddr_un addr;
+ int fd;
+ int len;
+ tinc_ctl_greeting_t greeting;
+ tinc_ctl_request_t req;
+
program_name = argv[0];
setlocale(LC_ALL, "");
@@ -399,6 +509,18 @@ int main(int argc, char *argv[], char *envp[]) {
return 1;
}
+ if(fullread(fd, &greeting, sizeof greeting) == -1) {
+ fprintf(stderr, _("Cannot read greeting from control socket:
%s\n"),
+ strerror(errno));
+ return 1;
+ }
+
+ if(greeting.version != TINC_CTL_VERSION_CURRENT) {
+ fprintf(stderr, _("Version mismatch: server %d, client %d\n"),
+ greeting.version, TINC_CTL_VERSION_CURRENT);
+ return 1;
+ }
+
struct ucred cred;
socklen_t credlen = sizeof cred;
@@ -413,18 +535,15 @@ int main(int argc, char *argv[], char *envp[]) {
}
if(!strcasecmp(argv[optind], "stop")) {
- write(fd, "stop\n", 5);
- return 0;
+ return send_ctl_request_cooked(fd, REQ_STOP, NULL, 0) != -1;
}
if(!strcasecmp(argv[optind], "reload")) {
- write(fd, "reload\n", 7);
- return 0;
+ return send_ctl_request_cooked(fd, REQ_RELOAD, NULL, 0) != -1;
}
if(!strcasecmp(argv[optind], "restart")) {
- write(fd, "restart\n", 8);
- return 0;
+ return send_ctl_request_cooked(fd, REQ_RESTART, NULL, 0) != -1;
}
fprintf(stderr, _("Unknown command `%s'.\n"), argv[optind]);
--
1.5.2.2.238.g7cbf2f2-dirty
-------------- next part -------------->From f8216cdf8a3cfcf9a9f1f9e5835f816cc7d50aad Mon Sep 17 00:00:00 2001
From: Scott Lamb <slamb@slamb.org>
Date: Sat, 21 Jul 2007 12:20:54 -0700
Subject: [PATCH] Purge through the control socket
---
doc/tinc.texi | 6 +++---
doc/tincctl.8.in | 2 ++
doc/tincd.8.in | 2 --
src/control.c | 6 ++++++
src/control_common.h | 1 +
src/net.c | 11 +----------
src/net.h | 2 +-
src/tincctl.c | 5 +++++
8 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/doc/tinc.texi b/doc/tinc.texi
index 541d2de..e953472 100644
--- a/doc/tinc.texi
+++ b/doc/tinc.texi
@@ -1569,9 +1569,6 @@ New outgoing connections specified in @file{tinc.conf}
will be made.
Temporarily increases debug level to 5.
Send this signal again to revert to the original level.
-@item WINCH
-Purges all information remembered about unreachable nodes.
-
@end table
@c =================================================================@@ -1854,6
+1851,9 @@ Dump a list of all meta connections with ourself.
@item dump graph
Dump a graph of the VPN in dotty format.
+@item purge
+Purges all information remembered about unreachable nodes.
+
@end table
diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in
index 734bb4f..40bd136 100644
--- a/doc/tincctl.8.in
+++ b/doc/tincctl.8.in
@@ -76,6 +76,8 @@ Dump a list of all meta connections with ourself.
Dump a graph of the VPN in
.Xr dotty 1
format.
+.It purge
+Purges all information remembered about unreachable nodes.
.El
.Sh BUGS
The "start", "restart", and "reload" commands are
not yet implemented.
diff --git a/doc/tincd.8.in b/doc/tincd.8.in
index f136a1b..96c773f 100644
--- a/doc/tincd.8.in
+++ b/doc/tincd.8.in
@@ -98,8 +98,6 @@ will be made.
.It INT
Temporarily increases debug level to 5.
Send this signal again to revert to the original level.
-.It WINCH
-Purges all information remembered about unreachable nodes.
.El
.Sh DEBUG LEVELS
The tinc daemon can send a lot of messages to the syslog.
diff --git a/src/control.c b/src/control.c
index 2009c22..a78f78a 100644
--- a/src/control.c
+++ b/src/control.c
@@ -95,6 +95,12 @@ static void handle_control_data(struct bufferevent *event,
void *data) {
goto respond;
}
+ if(req->type == REQ_PURGE) {
+ logger(LOG_NOTICE, _("Got '%s' command"),
"purge");
+ purge();
+ goto respond;
+ }
+
logger(LOG_DEBUG, _("Malformed control command received"));
res.res_errno = EINVAL;
diff --git a/src/control_common.h b/src/control_common.h
index 2ac208c..cbb8aa9 100644
--- a/src/control_common.h
+++ b/src/control_common.h
@@ -31,6 +31,7 @@ enum request_type {
REQ_DUMP_SUBNETS,
REQ_DUMP_CONNECTIONS,
REQ_DUMP_GRAPH,
+ REQ_PURGE,
};
#define TINC_CTL_VERSION_CURRENT 0
diff --git a/src/net.c b/src/net.c
index 3b180ff..d2b3134 100644
--- a/src/net.c
+++ b/src/net.c
@@ -41,7 +41,7 @@
/* Purge edges and subnets of unreachable nodes. Use carefully. */
-static void purge(void) {
+void purge(void) {
splay_node_t *nnode, *nnext, *enode, *enext, *snode, *snext;
node_t *n;
edge_t *e;
@@ -252,11 +252,6 @@ static void sigint_handler(int signal, short events, void
*data) {
}
}
-static void sigwinch_handler(int signal, short events, void *data) {
- logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
- purge();
-}
-
static void sighup_handler(int signal, short events, void *data) {
connection_t *c;
splay_node_t *node;
@@ -332,7 +327,6 @@ int main_loop(void) {
struct event sigint_event;
struct event sigterm_event;
struct event sigquit_event;
- struct event sigwinch_event;
struct event sigalrm_event;
cp();
@@ -347,8 +341,6 @@ int main_loop(void) {
signal_add(&sigterm_event, NULL);
signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL);
signal_add(&sigquit_event, NULL);
- signal_set(&sigwinch_event, SIGWINCH, sigwinch_handler, NULL);
- signal_add(&sigwinch_event, NULL);
signal_set(&sigalrm_event, SIGALRM, sigalrm_handler, NULL);
signal_add(&sigalrm_event, NULL);
@@ -361,7 +353,6 @@ int main_loop(void) {
signal_del(&sigint_event);
signal_del(&sigterm_event);
signal_del(&sigquit_event);
- signal_del(&sigwinch_event);
signal_del(&sigalrm_event);
event_del(&timeout_event);
diff --git a/src/net.h b/src/net.h
index 943b7e6..fd14c37 100644
--- a/src/net.h
+++ b/src/net.h
@@ -126,7 +126,6 @@ extern listen_socket_t listen_socket[MAXSOCKETS];
extern int listen_sockets;
extern int keylifetime;
extern bool do_prune;
-extern bool do_purge;
extern char *myport;
extern EVP_CIPHER_CTX packet_ctx;
@@ -156,6 +155,7 @@ extern void send_mtu_probe(struct node_t *);
extern void handle_device_data(int, short, void *);
extern void handle_meta_connection_data(int, short, void *);
extern void regenerate_key();
+extern void purge(void);
#ifndef HAVE_MINGW
#define closesocket(s) close(s)
diff --git a/src/tincctl.c b/src/tincctl.c
index 2e404d0..96f2ae2 100644
--- a/src/tincctl.c
+++ b/src/tincctl.c
@@ -89,6 +89,7 @@ static void usage(bool status) {
" subnets - all known subnets in the VPN\n"
" connections - all meta connections with
ourself\n"
" graph - graph of the VPN in dotty
format\n"
+ " purge Purge unreachable nodes\n"
"\n"));
printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
}
@@ -566,6 +567,10 @@ int main(int argc, char *argv[], char *envp[]) {
}
}
+ if(!strcasecmp(argv[optind], "purge")) {
+ return send_ctl_request_cooked(fd, REQ_PURGE, NULL, 0) != -1;
+ }
+
fprintf(stderr, _("Unknown command `%s'.\n"), argv[optind]);
usage(true);
--
1.5.2.2.238.g7cbf2f2-dirty
-------------- next part -------------->From d53fc7d4f6715a02427d7007a6445559fa27356e Mon Sep 17 00:00:00 2001
From: Scott Lamb <slamb@slamb.org>
Date: Sat, 21 Jul 2007 12:20:54 -0700
Subject: [PATCH] Retry connections through control socket
---
doc/tinc.texi | 14 +++++++-------
doc/tincctl.8.in | 12 ++++++++++++
doc/tincd.8.in | 12 ------------
src/control.c | 6 ++++++
src/control_common.h | 1 +
src/net.c | 8 +-------
src/net.h | 1 +
src/tincctl.c | 5 +++++
8 files changed, 33 insertions(+), 26 deletions(-)
diff --git a/doc/tinc.texi b/doc/tinc.texi
index b3f570c..9baf177 100644
--- a/doc/tinc.texi
+++ b/doc/tinc.texi
@@ -1553,13 +1553,6 @@ You can also send the following signals to a running
tincd process:
@c from the manpage
@table @samp
-@item ALRM
-Forces tinc to try to connect to all uplinks immediately.
-Usually tinc attempts to do this itself,
-but increases the time it waits between the attempts each time it failed,
-and if tinc didn't succeed to connect to an uplink the first time after it
started,
-it defaults to the maximum time of 15 minutes.
-
@item HUP
Partially rereads configuration files.
Connections to hosts whose host config file are removed are closed.
@@ -1853,6 +1846,13 @@ Purges all information remembered about unreachable
nodes.
@item debug @var{level}
Sets debug level to @var{level}.
+@item retry
+Forces tinc to try to connect to all uplinks immediately.
+Usually tinc attempts to do this itself,
+but increases the time it waits between the attempts each time it failed,
+and if tinc didn't succeed to connect to an uplink the first time after it
started,
+it defaults to the maximum time of 15 minutes.
+
@end table
diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in
index 623c908..899b066 100644
--- a/doc/tincctl.8.in
+++ b/doc/tincctl.8.in
@@ -81,6 +81,18 @@ Purges all information remembered about unreachable nodes.
.It debug Ar N
Sets debug level to
.Ar N .
+.It retry
+Forces
+.Xr tincd 8
+to try to connect to all uplinks immediately.
+Usually
+.Xr tincd 8
+attempts to do this itself,
+but increases the time it waits between the attempts each time it failed,
+and if
+.Xr tincd 8
+didn't succeed to connect to an uplink the first time after it started,
+it defaults to the maximum time of 15 minutes.
.El
.Sh BUGS
The "start", "restart", and "reload" commands are
not yet implemented.
diff --git a/doc/tincd.8.in b/doc/tincd.8.in
index b3142e8..e4bbaeb 100644
--- a/doc/tincd.8.in
+++ b/doc/tincd.8.in
@@ -77,18 +77,6 @@ Output version information and exit.
.El
.Sh SIGNALS
.Bl -tag -width indent
-.It ALRM
-Forces
-.Nm
-to try to connect to all uplinks immediately.
-Usually
-.Nm
-attempts to do this itself,
-but increases the time it waits between the attempts each time it failed,
-and if
-.Nm
-didn't succeed to connect to an uplink the first time after it started,
-it defaults to the maximum time of 15 minutes.
.It HUP
Partially rereads configuration files.
Connections to hosts whose host config file are removed are closed.
diff --git a/src/control.c b/src/control.c
index 775bb98..45ef51e 100644
--- a/src/control.c
+++ b/src/control.c
@@ -120,6 +120,12 @@ static void handle_control_data(struct bufferevent *event,
void *data) {
goto respond;
}
+ if(req->type == REQ_RETRY) {
+ logger(LOG_NOTICE, _("Got '%s' command"),
"retry");
+ retry();
+ goto respond;
+ }
+
logger(LOG_DEBUG, _("Malformed control command received"));
res.res_errno = EINVAL;
diff --git a/src/control_common.h b/src/control_common.h
index 40f6a50..6384651 100644
--- a/src/control_common.h
+++ b/src/control_common.h
@@ -33,6 +33,7 @@ enum request_type {
REQ_DUMP_GRAPH,
REQ_PURGE,
REQ_SET_DEBUG,
+ REQ_RETRY,
};
#define TINC_CTL_VERSION_CURRENT 0
diff --git a/src/net.c b/src/net.c
index a38c68b..2593628 100644
--- a/src/net.c
+++ b/src/net.c
@@ -279,9 +279,7 @@ static void sighup_handler(int signal, short events, void
*data) {
try_outgoing_connections();
}
-static void sigalrm_handler(int signal, short events, void *data) {
- logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
-
+void retry(void) {
connection_t *c;
splay_node_t *node;
@@ -307,7 +305,6 @@ int main_loop(void) {
struct event sighup_event;
struct event sigterm_event;
struct event sigquit_event;
- struct event sigalrm_event;
cp();
@@ -319,8 +316,6 @@ int main_loop(void) {
signal_add(&sigterm_event, NULL);
signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL);
signal_add(&sigquit_event, NULL);
- signal_set(&sigalrm_event, SIGALRM, sigalrm_handler, NULL);
- signal_add(&sigalrm_event, NULL);
if(event_loop(0) < 0) {
logger(LOG_ERR, _("Error while waiting for input: %s"),
strerror(errno));
@@ -330,7 +325,6 @@ int main_loop(void) {
signal_del(&sighup_event);
signal_del(&sigterm_event);
signal_del(&sigquit_event);
- signal_del(&sigalrm_event);
event_del(&timeout_event);
return 0;
diff --git a/src/net.h b/src/net.h
index fd14c37..b8e9e37 100644
--- a/src/net.h
+++ b/src/net.h
@@ -156,6 +156,7 @@ extern void handle_device_data(int, short, void *);
extern void handle_meta_connection_data(int, short, void *);
extern void regenerate_key();
extern void purge(void);
+extern void retry(void);
#ifndef HAVE_MINGW
#define closesocket(s) close(s)
diff --git a/src/tincctl.c b/src/tincctl.c
index bd82ec4..e276445 100644
--- a/src/tincctl.c
+++ b/src/tincctl.c
@@ -91,6 +91,7 @@ static void usage(bool status) {
" graph - graph of the VPN in dotty
format\n"
" purge Purge unreachable nodes\n"
" debug N Set debug level\n"
+ " retry Retry all outgoing connections\n"
"\n"));
printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
}
@@ -584,6 +585,10 @@ int main(int argc, char *argv[], char *envp[]) {
sizeof(debuglevel)) != -1;
}
+ if(!strcasecmp(argv[optind], "retry")) {
+ return send_ctl_request_cooked(fd, REQ_RETRY, NULL, 0) != -1;
+ }
+
fprintf(stderr, _("Unknown command `%s'.\n"), argv[optind]);
usage(true);
--
1.5.2.2.238.g7cbf2f2-dirty
-------------- next part -------------->From 17d66c92133b0956e508b4a4f43daa19413ec81f Mon Sep 17 00:00:00 2001
From: Scott Lamb <slamb@slamb.org>
Date: Sat, 21 Jul 2007 12:18:29 -0700
Subject: [PATCH] Update documentation to match tincctl changes
---
doc/Makefile.am | 12 ++++-
doc/tinc.texi | 117 +++++++++++++++++++++++++++++++++++++++++++++--------
doc/tincctl.8.in | 104 ++++++++++++++++++++++++++++++++++++++++++++++++
doc/tincd.8.in | 32 ++++-----------
src/tincd.c | 1 +
5 files changed, 221 insertions(+), 45 deletions(-)
create mode 100644 doc/tincctl.8.in
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 7c49d84..66de6d9 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -2,11 +2,11 @@
info_TEXINFOS = tinc.texi
-man_MANS = tincd.8 tinc.conf.5
+man_MANS = tincd.8 tincctl.8 tinc.conf.5
-EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.conf.5.in sample-config.tar.gz
+EXTRA_DIST = tincinclude.texi.in tincd.8.in tincctl.8.in tinc.conf.5.in
sample-config.tar.gz
-CLEANFILES = *.html tinc.info tincd.8 tinc.conf.5 tincinclude.texi
+CLEANFILES = *.html tinc.info tincd.8 tincctl.8 tinc.conf.5 tincinclude.texi
# Use `ginstall' in the definition of man_MANS to avoid
# confusion with the `install' target. The install rule transforms
`ginstall'
@@ -25,6 +25,9 @@ texi2html: tinc.texi
tincd.8.html: tincd.8
w3mman2html $< > $@
+tincctl.8.html: tincctl.8
+ w3mman2html $< > $@
+
tinc.conf.5.html: tinc.conf.5
w3mman2html $< > $@
@@ -37,6 +40,9 @@ substitute = sed \
tincd.8: tincd.8.in
$(substitute) tincd.8.in > tincd.8
+tincctl.8: tincctl.8.in
+ $(substitute) tincctl.8.in > tincctl.8
+
tinc.conf.5: tinc.conf.5.in
$(substitute) tinc.conf.5.in > tinc.conf.5
diff --git a/doc/tinc.texi b/doc/tinc.texi
index c968eb3..2ea54be 100644
--- a/doc/tinc.texi
+++ b/doc/tinc.texi
@@ -71,6 +71,7 @@ permission notice identical to this one.
* Installation::
* Configuration::
* Running tinc::
+* Controlling tinc::
* Technical information::
* Platform specific information::
* About us::
@@ -981,7 +982,7 @@ accidental eavesdropping if you are editting the
configuration file.
@cindex PrivateKeyFile
@item PrivateKeyFile = <@var{path}>
(@file{@value{sysconfdir}/tinc/@var{netname}/rsa_key.priv})
This is the full path name of the RSA private key file that was
-generated by @samp{tincd --generate-keys}. It must be a full path, not a
+generated by @samp{tincctl generate-keys}. It must be a full path, not a
relative directory.
Note that there must be exactly one of PrivateKey
@@ -1053,7 +1054,7 @@ This is the RSA public key for this host.
@cindex PublicKeyFile
@item PublicKeyFile = <@var{path}> [obsolete]
This is the full path name of the RSA public key file that was generated
-by @samp{tincd --generate-keys}. It must be a full path, not a relative
+by @samp{tincctl generate-keys}. It must be a full path, not a relative
directory.
@cindex PEM format
@@ -1230,7 +1231,7 @@ Now that you have already created the main configuration
file and your host conf
you can easily create a public/private keypair by entering the following
command:
@example
-tincd -n @var{netname} -K
+tincctl -n @var{netname} generate-keys
@end example
Tinc will generate a public and a private key and ask you where to put them.
@@ -1459,7 +1460,7 @@ Address = 4.5.6.7
A, B, C and D all have generated a public/private keypair with the following
command:
@example
-tincd -n company -K
+tincctl -n company generate-keys
@end example
The private key is stored in
@file{@value{sysconfdir}/tinc/company/rsa_key.priv},
@@ -1525,20 +1526,12 @@ This will also disable the automatic restart mechanism
for fatal errors.
Set debug level to @var{level}. The higher the debug level, the more gets
logged. Everything goes via syslog.
-@item -k, --kill[=@var{signal}]
-Attempt to kill a running tincd (optionally with the specified @var{signal}
instead of SIGTERM) and exit.
-Use it in conjunction with the -n option to make sure you kill the right tinc
daemon.
-Under native Windows the optional argument is ignored,
-the service will always be stopped and removed.
-
@item -n, --net=@var{netname}
Use configuration for net @var{netname}. @xref{Multiple networks}.
-@item -K, --generate-keys[=@var{bits}]
-Generate public/private keypair of @var{bits} length. If @var{bits} is not
specified,
-1024 is the default. tinc will ask where you want to store the files,
-but will default to the configuration directory (you can use the -c or -n
option
-in combination with -K). After that, tinc will quit.
+@item --controlsocket=@var{filename}
+Open control socket at @var{filename}. If unspecified, the default is
+@file{@value{localstatedir}/run/tinc.@var{netname}.control}.
@item -L, --mlock
Lock tinc into main memory.
@@ -1548,9 +1541,6 @@ This will prevent sensitive data like shared private keys
to be written to the s
Write log entries to a file instead of to the system logging facility.
If @var{file} is omitted, the default is
@file{@value{localstatedir}/log/tinc.@var{netname}.log}.
-@item --pidfile=@var{file}
-Write PID to @var{file} instead of
@file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
-
@item --bypass-security
Disables encryption and authentication.
Only useful for debugging.
@@ -1793,6 +1783,97 @@ Be sure to include the following information in your
bugreport:
@end itemize
@c =================================================================+@node
Controlling tinc
+@chapter Controlling tinc
+
+You can control and inspect a running @samp{tincd} through the @samp{tincctl}
+command. A quick example:
+
+@example
+tincctl -n @var{netname} reload
+@end example
+
+@menu
+* tincctl runtime options::
+* tincctl commands::
+@end menu
+
+
+@c =================================================================+@node
tincctl runtime options
+@section tincctl runtime options
+
+@c from the manpage
+@table @option
+@item -c, --config=@var{path}
+Read configuration options from the directory @var{path}. The default is
+@file{@value{sysconfdir}/tinc/@var{netname}/}.
+
+@item -n, --net=@var{netname}
+Use configuration for net @var{netname}. @xref{Multiple networks}.
+
+@item --controlsocket=@var{filename}
+Open control socket at @var{filename}. If unspecified, the default is
+@file{@value{localstatedir}/run/tinc.@var{netname}.control}.
+
+@item --help
+Display a short reminder of runtime options and commands, then terminate.
+
+@item --version
+Output version information and exit.
+
+@end table
+
+
+@c =================================================================+@node
tincctl commands
+@section tincctl commands
+
+@c from the manpage
+@table @code
+
+@item start
+Start @samp{tincd}.
+
+@item stop
+Stop @samp{tincd}.
+
+@item restart
+Restart @samp{tincd}.
+
+@item reload
+Partially rereads configuration files. Connections to hosts whose host
+config files are removed are closed. New outgoing connections specified
+in @file{tinc.conf} will be made.
+
+@item pid
+Shows the PID of the currently running @samp{tincd}.
+
+@item generate-keys [@var{bits}]
+Generate public/private keypair of @var{bits} length. If @var{bits} is not
specified,
+1024 is the default. tinc will ask where you want to store the files,
+but will default to the configuration directory (you can use the -c or -n
+option).
+
+@item dump nodes
+Dump a list of all known nodes in the VPN.
+
+@item dump edges
+Dump a list of all known connections in the VPN.
+
+@item dump subnets
+Dump a list of all known subnets in the VPN.
+
+@item dump connections
+Dump a list of all meta connections with ourself.
+
+@item dump graph
+Dump a graph of the VPN in dotty format.
+
+@end table
+
+
+@c ================================================================= @node
Technical information
@chapter Technical information
diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in
new file mode 100644
index 0000000..eeb5031
--- /dev/null
+++ b/doc/tincctl.8.in
@@ -0,0 +1,104 @@
+.Dd 2007-07-20
+.Dt TINCCTL 8
+.\" Manual page created by:
+.\" Scott Lamb
+.Sh NAME
+.Nm tincctl
+.Nd tinc VPN control
+.Sh SYNOPSIS
+.Nm
+.Op Fl cn
+.Op Fl -config Ns = Ns Ar DIR
+.Op Fl -net Ns = Ns Ar NETNAME
+.Op Fl -controlsocket Ns = Ns Ar FILENAME
+.Op Fl -help
+.Op Fl -version
+.Ar COMMAND
+.Sh DESCRIPTION
+This is the control program of tinc, a secure virtual private network (VPN)
+project.
+.Nm
+communicates with
+.Xr tincd 8
+to alter and inspect the running VPN's state.
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl n, -net Ns = Ns Ar NETNAME
+Communicate with tincd(8) connected with
+.Ar NETNAME .
+.It Fl -controlsocket Ns = Ns Ar FILENAME
+Open control socket at
+.Ar FILENAME .
+If unspecified, the default is
+.Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .control.
+.It Fl -help
+Display short list of options.
+.It Fl -version
+Output version information and exit.
+.El
+.Sh COMMANDS
+.zZ
+.Bl -tag -width indent
+.It start
+Start
+.Xr tincd 8 .
+.It stop
+Stop
+.Xr tincd 8 .
+.It restart
+Restart
+.Xr tincd 8 .
+.It reload
+Partially rereads configuration files. Connections to hosts whose host
+config files are removed are closed. New outgoing connections specified
+in
+.Xr tinc.conf 5
+will be made.
+.It pid
+Shows the PID of the currently running
+.Xr tincd 8 .
+.It generate-keys Op bits
+Generate public/private RSA keypair and exit.
+If
+.Ar bits
+is omitted, the default length will be 1024 bits.
+When saving keys to existing files, tinc will not delete the old keys;
+you have to remove them manually.
+.It dump nodes
+Dump a list of all known nodes in the VPN.
+.It dump edges
+Dump a list of all known connections in the VPN.
+.It dump subnets
+Dump a list of all known subnets in the VPN.
+.It dump connections
+Dump a list of all meta connections with ourself.
+.It dump graph
+Dump a graph of the VPN in
+.Xr dotty 1
+format.
+.El
+.Sh BUGS
+The "start", "restart", "reload", and
"dump" commands are not yet implemented.
+.Pp
+If you find any bugs, report them to tinc@tinc-vpn.org.
+.Sh SEE ALSO
+.Xr tincd 8 ,
+.Xr tinc.conf 5 ,
+.Xr dotty 1 ,
+.Pa http://www.tinc-vpn.org/ ,
+.Pa http://www.cabal.org/ .
+.Pp
+The full documentation for tinc is maintained as a Texinfo manual.
+If the info and tinc programs are properly installed at your site,
+the command
+.Ic info tinc
+should give you access to the complete manual.
+.Pp
+tinc comes with ABSOLUTELY NO WARRANTY.
+This is free software, and you are welcome to redistribute it under certain
conditions;
+see the file COPYING for details.
+.Sh AUTHORS
+.An "Ivo Timmermans"
+.An "Guus Sliepen" Aq guus@tinc-vpn.org
+.Pp
+And thanks to many others for their contributions to tinc!
diff --git a/doc/tincd.8.in b/doc/tincd.8.in
index 97654f3..37a134e 100644
--- a/doc/tincd.8.in
+++ b/doc/tincd.8.in
@@ -8,16 +8,13 @@
.Nd tinc VPN daemon
.Sh SYNOPSIS
.Nm
-.Op Fl cdDkKnL
+.Op Fl cdDKnL
.Op Fl -config Ns = Ns Ar DIR
.Op Fl -no-detach
.Op Fl -debug Ns Op = Ns Ar LEVEL
-.Op Fl -kill Ns Op = Ns Ar SIGNAL
.Op Fl -net Ns = Ns Ar NETNAME
-.Op Fl -generate-keys Ns Op = Ns Ar BITS
.Op Fl -mlock
.Op Fl -logfile Ns Op = Ns Ar FILE
-.Op Fl -pidfile Ns = Ns Ar FILE
.Op Fl -bypass-security
.Op Fl -help
.Op Fl -version
@@ -51,24 +48,9 @@ If not mentioned otherwise, this will show log messages on
the standard error ou
Increase debug level or set it to
.Ar LEVEL
(see below).
-.It Fl k, -kill Ns Op = Ns Ar SIGNAL
-Attempt to kill a running
-.Nm
-(optionally with the specified
-.Ar SIGNAL
-instead of SIGTERM) and exit.
-Under Windows (not Cygwin) the optional argument is ignored,
-the service will always be stopped and removed.
.It Fl n, -net Ns = Ns Ar NETNAME
Connect to net
.Ar NETNAME .
-.It Fl K, -generate-keys Ns Op = Ns Ar BITS
-Generate public/private RSA keypair and exit.
-If
-.Ar BITS
-is omitted, the default length will be 1024 bits.
-When saving keys to existing files, tinc will not delete the old keys,
-you have to remove them manually.
.It Fl L, -mlock
Lock tinc into main memory.
This will prevent sensitive data like shared private keys to be written to the
system swap files/partitions.
@@ -78,12 +60,13 @@ If
.Ar FILE
is omitted, the default is
.Pa @localstatedir@/log/tinc. Ns Ar NETNAME Ns Pa .log.
-.It Fl -pidfile Ns = Ns Ar FILE
-Write PID to
+.It Fl -controlsocket Ns = Ns Ar FILENAME
+Open control socket at
+.Ar FILENAME .
+If
.Ar FILE
-instead of
-.Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .pid.
-Under Windows this option will be ignored.
+is omitted, the default is
+.Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .control.
.It Fl -bypass-security
Disables encryption and authentication of the meta protocol.
Only useful for debugging.
@@ -167,6 +150,7 @@ If you find any bugs, report them to tinc@tinc-vpn.org.
.Sh TODO
A lot, especially security auditing.
.Sh SEE ALSO
+.Xr tincctl 8 ,
.Xr tinc.conf 5 ,
.Pa http://www.tinc-vpn.org/ ,
.Pa http://www.cabal.org/ .
diff --git a/src/tincd.c b/src/tincd.c
index 95c45d3..65c452a 100644
--- a/src/tincd.c
+++ b/src/tincd.c
@@ -109,6 +109,7 @@ static void usage(bool status)
" -L, --mlock Lock tinc into main memory.\n"
" --logfile[=FILENAME] Write log entries to a
logfile.\n"
" --controlsocket=FILENAME Open control socket at
FILENAME.\n"
+ " --bypass-security Disables meta protocol security, for
debugging.\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"));
--
1.5.2.2.238.g7cbf2f2-dirty
-------------- next part -------------->From c30f4103d030826de267b20561f1677d4d0de3ad Mon Sep 17 00:00:00 2001
From: Scott Lamb <slamb@slamb.org>
Date: Sat, 21 Jul 2007 12:20:54 -0700
Subject: [PATCH] Alter debugging levels through control socket
---
doc/tinc.texi | 7 +++----
doc/tincctl.8.in | 3 +++
doc/tincd.8.in | 3 ---
src/control.c | 19 +++++++++++++++++++
src/control_common.h | 1 +
src/net.c | 23 -----------------------
src/tincctl.c | 13 +++++++++++++
7 files changed, 39 insertions(+), 30 deletions(-)
diff --git a/doc/tinc.texi b/doc/tinc.texi
index e953472..b3f570c 100644
--- a/doc/tinc.texi
+++ b/doc/tinc.texi
@@ -1565,10 +1565,6 @@ Partially rereads configuration files.
Connections to hosts whose host config file are removed are closed.
New outgoing connections specified in @file{tinc.conf} will be made.
-@item INT
-Temporarily increases debug level to 5.
-Send this signal again to revert to the original level.
-
@end table
@c =================================================================@@ -1854,6
+1850,9 @@ Dump a graph of the VPN in dotty format.
@item purge
Purges all information remembered about unreachable nodes.
+@item debug @var{level}
+Sets debug level to @var{level}.
+
@end table
diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in
index 40bd136..623c908 100644
--- a/doc/tincctl.8.in
+++ b/doc/tincctl.8.in
@@ -78,6 +78,9 @@ Dump a graph of the VPN in
format.
.It purge
Purges all information remembered about unreachable nodes.
+.It debug Ar N
+Sets debug level to
+.Ar N .
.El
.Sh BUGS
The "start", "restart", and "reload" commands are
not yet implemented.
diff --git a/doc/tincd.8.in b/doc/tincd.8.in
index 96c773f..b3142e8 100644
--- a/doc/tincd.8.in
+++ b/doc/tincd.8.in
@@ -95,9 +95,6 @@ Connections to hosts whose host config file are removed are
closed.
New outgoing connections specified in
.Pa tinc.conf
will be made.
-.It INT
-Temporarily increases debug level to 5.
-Send this signal again to revert to the original level.
.El
.Sh DEBUG LEVELS
The tinc daemon can send a lot of messages to the syslog.
diff --git a/src/control.c b/src/control.c
index a78f78a..775bb98 100644
--- a/src/control.c
+++ b/src/control.c
@@ -101,6 +101,25 @@ static void handle_control_data(struct bufferevent *event,
void *data) {
goto respond;
}
+ if(req->type == REQ_SET_DEBUG) {
+ debug_t new_debug_level;
+
+ logger(LOG_NOTICE, _("Got '%s' command"),
"debug");
+ if(req->length != sizeof(*req) + sizeof debug_level)
+ res.res_errno = EINVAL;
+ else {
+ memcpy(&new_debug_level, req + 1, sizeof(debug_t));
+ logger(LOG_NOTICE, _("Changing debug level from %d to %d"),
+ debug_level, new_debug_level);
+ if(evbuffer_add_printf(res_data,
+ _("Changing debug level from %d to %d\n"),
+ debug_level, new_debug_level) == -1)
+ res.res_errno = errno;
+ debug_level = new_debug_level;
+ }
+ goto respond;
+ }
+
logger(LOG_DEBUG, _("Malformed control command received"));
res.res_errno = EINVAL;
diff --git a/src/control_common.h b/src/control_common.h
index cbb8aa9..40f6a50 100644
--- a/src/control_common.h
+++ b/src/control_common.h
@@ -32,6 +32,7 @@ enum request_type {
REQ_DUMP_CONNECTIONS,
REQ_DUMP_GRAPH,
REQ_PURGE,
+ REQ_SET_DEBUG,
};
#define TINC_CTL_VERSION_CURRENT 0
diff --git a/src/net.c b/src/net.c
index d2b3134..a38c68b 100644
--- a/src/net.c
+++ b/src/net.c
@@ -233,25 +233,6 @@ static void sigterm_handler(int signal, short events, void
*data) {
event_loopexit(NULL);
}
-static void sigint_handler(int signal, short events, void *data) {
- static int saved_debug_level = -1;
-
- logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
-
- if(saved_debug_level != -1) {
- logger(LOG_NOTICE, _("Reverting to old debug level (%d)"),
- saved_debug_level);
- debug_level = saved_debug_level;
- saved_debug_level = -1;
- } else {
- logger(LOG_NOTICE,
- _("Temporarily setting debug level to 5. Kill me with SIGINT again to
go back to level %d."),
- debug_level);
- saved_debug_level = debug_level;
- debug_level = 5;
- }
-}
-
static void sighup_handler(int signal, short events, void *data) {
connection_t *c;
splay_node_t *node;
@@ -324,7 +305,6 @@ static void sigalrm_handler(int signal, short events, void
*data) {
int main_loop(void) {
struct event timeout_event;
struct event sighup_event;
- struct event sigint_event;
struct event sigterm_event;
struct event sigquit_event;
struct event sigalrm_event;
@@ -335,8 +315,6 @@ int main_loop(void) {
event_add(&timeout_event, &(struct timeval){pingtimeout, 0});
signal_set(&sighup_event, SIGHUP, sighup_handler, NULL);
signal_add(&sighup_event, NULL);
- signal_set(&sigint_event, SIGINT, sigint_handler, NULL);
- signal_add(&sigint_event, NULL);
signal_set(&sigterm_event, SIGTERM, sigterm_handler, NULL);
signal_add(&sigterm_event, NULL);
signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL);
@@ -350,7 +328,6 @@ int main_loop(void) {
}
signal_del(&sighup_event);
- signal_del(&sigint_event);
signal_del(&sigterm_event);
signal_del(&sigquit_event);
signal_del(&sigalrm_event);
diff --git a/src/tincctl.c b/src/tincctl.c
index 96f2ae2..bd82ec4 100644
--- a/src/tincctl.c
+++ b/src/tincctl.c
@@ -90,6 +90,7 @@ static void usage(bool status) {
" connections - all meta connections with
ourself\n"
" graph - graph of the VPN in dotty
format\n"
" purge Purge unreachable nodes\n"
+ " debug N Set debug level\n"
"\n"));
printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
}
@@ -571,6 +572,18 @@ int main(int argc, char *argv[], char *envp[]) {
return send_ctl_request_cooked(fd, REQ_PURGE, NULL, 0) != -1;
}
+ if(!strcasecmp(argv[optind], "debug")) {
+ int debuglevel;
+
+ if(argc != optind + 2) {
+ fprintf(stderr, "Invalid arguments.\n");
+ return 1;
+ }
+ debuglevel = atoi(argv[optind+1]);
+ return send_ctl_request_cooked(fd, REQ_SET_DEBUG, &debuglevel,
+ sizeof(debuglevel)) != -1;
+ }
+
fprintf(stderr, _("Unknown command `%s'.\n"), argv[optind]);
usage(true);
--
1.5.2.2.238.g7cbf2f2-dirty
-------------- next part -------------->From 2384bfa9bd5a1447ce645fa07bdf492bc6be9937 Mon Sep 17 00:00:00 2001
From: Scott Lamb <slamb@slamb.org>
Date: Sat, 21 Jul 2007 12:20:54 -0700
Subject: [PATCH] Reload configuration through control socket
I also kept the SIGHUP handler, which many people will expect to see.
The control socket is better, though - it will tell you if there is a
problem.
---
doc/tincctl.8.in | 8 +++++++-
src/control.c | 6 ++++++
src/net.c | 11 ++++++++---
src/net.h | 1 +
src/tincctl.c | 5 +++++
5 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in
index 899b066..493adfd 100644
--- a/doc/tincctl.8.in
+++ b/doc/tincctl.8.in
@@ -93,9 +93,15 @@ and if
.Xr tincd 8
didn't succeed to connect to an uplink the first time after it started,
it defaults to the maximum time of 15 minutes.
+.It reload
+Partially rereads configuration files.
+Connections to hosts whose host config files are removed are closed.
+New outgoing connections specified in
+.Pa tinc.conf
+will be made.
.El
.Sh BUGS
-The "start", "restart", and "reload" commands are
not yet implemented.
+The "start" and "restart" commands are not yet implemented.
.Pp
If you find any bugs, report them to tinc@tinc-vpn.org.
.Sh SEE ALSO
diff --git a/src/control.c b/src/control.c
index 45ef51e..5665cbb 100644
--- a/src/control.c
+++ b/src/control.c
@@ -126,6 +126,12 @@ static void handle_control_data(struct bufferevent *event,
void *data) {
goto respond;
}
+ if(req->type == REQ_RELOAD) {
+ logger(LOG_NOTICE, _("Got '%s' command"),
"reload");
+ res.res_errno = reload_configuration();
+ goto respond;
+ }
+
logger(LOG_DEBUG, _("Malformed control command received"));
res.res_errno = EINVAL;
diff --git a/src/net.c b/src/net.c
index 2593628..fb06c8a 100644
--- a/src/net.c
+++ b/src/net.c
@@ -234,13 +234,16 @@ static void sigterm_handler(int signal, short events, void
*data) {
}
static void sighup_handler(int signal, short events, void *data) {
+ logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
+ reload_configuration();
+}
+
+int reload_configuration(void) {
connection_t *c;
splay_node_t *node;
char *fname;
struct stat s;
static time_t last_config_check = 0;
-
- logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
/* Reread our own configuration file */
@@ -250,7 +253,7 @@ static void sighup_handler(int signal, short events, void
*data) {
if(!read_server_config()) {
logger(LOG_ERR, _("Unable to reread configuration file,
exitting."));
event_loopexit(NULL);
- return;
+ return EINVAL;
}
/* Close connections to hosts that have a changed or deleted host config file
*/
@@ -277,6 +280,8 @@ static void sighup_handler(int signal, short events, void
*data) {
/* Try to make outgoing connections */
try_outgoing_connections();
+
+ return 0;
}
void retry(void) {
diff --git a/src/net.h b/src/net.h
index b8e9e37..c97d931 100644
--- a/src/net.h
+++ b/src/net.h
@@ -157,6 +157,7 @@ extern void handle_meta_connection_data(int, short, void *);
extern void regenerate_key();
extern void purge(void);
extern void retry(void);
+extern int reload_configuration(void);
#ifndef HAVE_MINGW
#define closesocket(s) close(s)
diff --git a/src/tincctl.c b/src/tincctl.c
index e276445..c254d51 100644
--- a/src/tincctl.c
+++ b/src/tincctl.c
@@ -92,6 +92,7 @@ static void usage(bool status) {
" purge Purge unreachable nodes\n"
" debug N Set debug level\n"
" retry Retry all outgoing connections\n"
+ " reload Partial reload of configuration\n"
"\n"));
printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
}
@@ -589,6 +590,10 @@ int main(int argc, char *argv[], char *envp[]) {
return send_ctl_request_cooked(fd, REQ_RETRY, NULL, 0) != -1;
}
+ if(!strcasecmp(argv[optind], "reload")) {
+ return send_ctl_request_cooked(fd, REQ_RELOAD, NULL, 0) != -1;
+ }
+
fprintf(stderr, _("Unknown command `%s'.\n"), argv[optind]);
usage(true);
--
1.5.2.2.238.g7cbf2f2-dirty