+ graph_changed = true;
+}
+
+
+
+/* Dump nodes and edges to a graphviz file.
+
+ The file can be converted to an image with
+ dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true
+*/
+
+void dump_graph(void)
+{
+ avl_node_t *node;
+ node_t *n;
+ edge_t *e;
+ char *filename = NULL, *tmpname = NULL;
+ FILE *file;
+
+ if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename))
+ return;
+
+ graph_changed = false;
+
+ 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");
+
+ /* 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);
+ }
+
+ /* 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);
+ }
+
+ fprintf(file, "}\n");
+
+ fclose(file);
+
+ if(filename[0] != '|') {
+ rename(tmpname, filename);
+ free(tmpname);
+ }