Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/ngctl/dot.c
/* | /* | ||||
* dot.c | * dot.c | ||||
* | * | ||||
* Copyright (c) 2019 Lutz Donnerhacke | |||||
* Copyright (c) 2004 Brian Fundakowski Feldman | * Copyright (c) 2004 Brian Fundakowski Feldman | ||||
* Copyright (c) 1996-1999 Whistle Communications, Inc. | * Copyright (c) 1996-1999 Whistle Communications, Inc. | ||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Subject to the following obligations and disclaimer of warranty, use and | * Subject to the following obligations and disclaimer of warranty, use and | ||||
* redistribution of this software, in source or object code forms, with or | * redistribution of this software, in source or object code forms, with or | ||||
* without modifications are expressly permitted by Whistle Communications; | * without modifications are expressly permitted by Whistle Communications; | ||||
* provided, however, that: | * provided, however, that: | ||||
Show All 35 Lines | |||||
#include "ngctl.h" | #include "ngctl.h" | ||||
#define UNNAMED "\\<unnamed\\>" | #define UNNAMED "\\<unnamed\\>" | ||||
static int DotCmd(int ac, char **av); | static int DotCmd(int ac, char **av); | ||||
const struct ngcmd dot_cmd = { | const struct ngcmd dot_cmd = { | ||||
DotCmd, | DotCmd, | ||||
"dot [outputfile]", | "dot [-c] [outputfile]", | ||||
"Produce a GraphViz (.dot) of the entire netgraph.", | "Produce a GraphViz (.dot) of the entire netgraph.", | ||||
"If no outputfile is specified, stdout will be assumed.", | "If no outputfile is specified, stdout will be assumed." | ||||
" The optional -c argument generates a graph without separate" | |||||
" structures for egde names. Such a graph is more compact.", | |||||
markj: Typo, "edge" | |||||
{ "graphviz", "confdot" } | { "graphviz", "confdot" } | ||||
}; | }; | ||||
static int | static int | ||||
DotCmd(int ac, char **av) | DotCmd(int ac, char **av) | ||||
{ | { | ||||
struct ng_mesg *nlresp; | struct ng_mesg *nlresp; | ||||
struct namelist *nlist; | struct namelist *nlist; | ||||
FILE *f = stdout; | FILE *f = stdout; | ||||
int ch; | int ch; | ||||
int compact = 0; | |||||
u_int i; | u_int i; | ||||
/* Get options */ | /* Get options */ | ||||
optind = 1; | optind = 1; | ||||
while ((ch = getopt(ac, av, "")) != -1) { | while ((ch = getopt(ac, av, "c")) != -1) { | ||||
switch (ch) { | switch (ch) { | ||||
case 'c': | |||||
compact = 1; | |||||
break; | |||||
case '?': | case '?': | ||||
default: | default: | ||||
return (CMDRTN_USAGE); | return (CMDRTN_USAGE); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
ac -= optind; | ac -= optind; | ||||
av += optind; | av += optind; | ||||
Show All 21 Lines | if (NgSendMsg(csock, ".", NGM_GENERIC_COOKIE, NGM_LISTNODES, NULL, | ||||
goto error; | goto error; | ||||
} | } | ||||
if (NgAllocRecvMsg(csock, &nlresp, NULL) < 0) { | if (NgAllocRecvMsg(csock, &nlresp, NULL) < 0) { | ||||
warn("recv listnodes msg"); | warn("recv listnodes msg"); | ||||
goto error; | goto error; | ||||
} | } | ||||
nlist = (struct namelist *)nlresp->data; | nlist = (struct namelist *)nlresp->data; | ||||
if (compact) { | |||||
fprintf(f, "digraph netgraph {\n"); | |||||
fprintf(f, "\tedge [ dir = \"none\", fontsize = 10 ];\n"); | |||||
} else { | |||||
fprintf(f, "graph netgraph {\n"); | fprintf(f, "graph netgraph {\n"); | ||||
/* TODO: implement rank = same or subgraphs at some point */ | /* TODO: implement rank = same or subgraphs at some point */ | ||||
fprintf(f, "\tedge [ weight = 1.0 ];\n"); | fprintf(f, "\tedge [ weight = 1.0 ];\n"); | ||||
} | |||||
Done Inline Actionsif<space>( afedorov: if<space>( | |||||
fprintf(f, "\tnode [ shape = record, fontsize = 12 ] {\n"); | fprintf(f, "\tnode [ shape = record, fontsize = 12 ] {\n"); | ||||
for (i = 0; i < nlist->numnames; i++) | for (i = 0; i < nlist->numnames; i++) | ||||
fprintf(f, "\t\t\"%jx\" [ label = \"{%s:|{%s|[%jx]:}}\" ];\n", | fprintf(f, "\t\t\"%jx\" [ label = \"{%s:|{%s|[%jx]:}}\" ];\n", | ||||
(uintmax_t)nlist->nodeinfo[i].id, | (uintmax_t)nlist->nodeinfo[i].id, | ||||
nlist->nodeinfo[i].name[0] != '\0' ? | nlist->nodeinfo[i].name[0] != '\0' ? | ||||
nlist->nodeinfo[i].name : UNNAMED, | nlist->nodeinfo[i].name : UNNAMED, | ||||
nlist->nodeinfo[i].type, (uintmax_t)nlist->nodeinfo[i].id); | nlist->nodeinfo[i].type, (uintmax_t)nlist->nodeinfo[i].id); | ||||
fprintf(f, "\t};\n"); | fprintf(f, "\t};\n"); | ||||
Show All 31 Lines | for (i = 0; i < nlist->numnames; i++) { | ||||
hlist = (struct hooklist *)hlresp->data; | hlist = (struct hooklist *)hlresp->data; | ||||
ninfo = &hlist->nodeinfo; | ninfo = &hlist->nodeinfo; | ||||
if (ninfo->hooks == 0) { | if (ninfo->hooks == 0) { | ||||
free(hlresp); | free(hlresp); | ||||
continue; | continue; | ||||
} | } | ||||
if (!compact) { | |||||
fprintf(f, "\tnode [ shape = octagon, fontsize = 10 ] {\n"); | fprintf(f, "\tnode [ shape = octagon, fontsize = 10 ] {\n"); | ||||
for (j = 0; j < ninfo->hooks; j++) | for (j = 0; j < ninfo->hooks; j++) | ||||
fprintf(f, "\t\t\"%jx.%s\" [ label = \"%s\" ];\n", | fprintf(f, "\t\t\"%jx.%s\" [ label = \"%s\" ];\n", | ||||
Done Inline ActionsIndentation around these needs reassessed; fprintf should be tabbed over from the level of the line above rather than the current two spaces, then the following lines; ditto for the next loop+fprintf construct. kevans: Indentation around these needs reassessed; fprintf should be tabbed over from the level of the… | |||||
(uintmax_t)nlist->nodeinfo[i].id, | (uintmax_t)nlist->nodeinfo[i].id, | ||||
hlist->link[j].ourhook, hlist->link[j].ourhook); | hlist->link[j].ourhook, hlist->link[j].ourhook); | ||||
Done Inline ActionsSame note about indentation as below, it looks wrong here. markj: Same note about indentation as below, it looks wrong here. | |||||
fprintf(f, "\t};\n"); | fprintf(f, "\t};\n"); | ||||
Done Inline ActionsThis line should be cleared kevans: This line should be cleared | |||||
fprintf(f, "\t{\n\t\tedge [ weight = 2.0, style = bold ];\n"); | fprintf(f, "\t{\n\t\tedge [ weight = 2.0, style = bold ];\n"); | ||||
for (j = 0; j < ninfo->hooks; j++) | for (j = 0; j < ninfo->hooks; j++) | ||||
fprintf(f, "\t\t\"%jx\" -- \"%jx.%s\";\n", | fprintf(f, "\t\t\"%jx\" -- \"%jx.%s\";\n", | ||||
(uintmax_t)nlist->nodeinfo[i].id, | (uintmax_t)nlist->nodeinfo[i].id, | ||||
(uintmax_t)nlist->nodeinfo[i].id, | (uintmax_t)nlist->nodeinfo[i].id, | ||||
hlist->link[j].ourhook); | hlist->link[j].ourhook); | ||||
fprintf(f, "\t};\n"); | fprintf(f, "\t};\n"); | ||||
} | |||||
Done Inline ActionsDitto afedorov: Ditto | |||||
for (j = 0; j < ninfo->hooks; j++) { | for (j = 0; j < ninfo->hooks; j++) { | ||||
/* Only print the edges going in one direction. */ | /* Only print the edges going in one direction. */ | ||||
if (hlist->link[j].nodeinfo.id > nlist->nodeinfo[i].id) | if (hlist->link[j].nodeinfo.id > nlist->nodeinfo[i].id) | ||||
continue; | continue; | ||||
if (compact) { | |||||
fprintf(f, "\t\"%jx\" -> \"%jx\" [ headlabel = \"%s\", taillabel =\"%s\" ] ;\n", | |||||
Done Inline ActionsMissing a space after the second "=" markj: Missing a space after the second "=" | |||||
(uintmax_t)hlist->link[j].nodeinfo.id, | |||||
(uintmax_t)nlist->nodeinfo[i].id, | |||||
hlist->link[j].ourhook, | |||||
hlist->link[j].peerhook); | |||||
} else { | |||||
fprintf(f, "\t\"%jx.%s\" -- \"%jx.%s\";\n", | fprintf(f, "\t\"%jx.%s\" -- \"%jx.%s\";\n", | ||||
(uintmax_t)nlist->nodeinfo[i].id, | (uintmax_t)nlist->nodeinfo[i].id, | ||||
hlist->link[j].ourhook, | hlist->link[j].ourhook, | ||||
(uintmax_t)hlist->link[j].nodeinfo.id, | (uintmax_t)hlist->link[j].nodeinfo.id, | ||||
hlist->link[j].peerhook); | hlist->link[j].peerhook); | ||||
Done Inline ActionsThe indentation of the continuing lines is wrong, it should be by four spaces per style(9). markj: The indentation of the continuing lines is wrong, it should be by four spaces per style(9). | |||||
} | |||||
Done Inline ActionsDitto afedorov: Ditto | |||||
} | } | ||||
free(hlresp); | free(hlresp); | ||||
} | } | ||||
fprintf(f, "}\n"); | fprintf(f, "}\n"); | ||||
free(nlresp); | free(nlresp); | ||||
if (f != stdout) | if (f != stdout) | ||||
(void)fclose(f); | (void)fclose(f); | ||||
return (CMDRTN_OK); | return (CMDRTN_OK); | ||||
error: | error: | ||||
if (f != stdout) | if (f != stdout) | ||||
(void)fclose(f); | (void)fclose(f); | ||||
return (CMDRTN_ERROR); | return (CMDRTN_ERROR); | ||||
} | } |
Typo, "edge"