File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bmon / src / out_html.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:19:56 2012 UTC (13 years, 4 months ago) by misho
Branches: bmon, MAIN
CVS tags: v2_1_0p0, v2_1_0, HEAD
bmon

    1: /*
    2:  * out_html.c                      HTML Output
    3:  *
    4:  * Copyright (c) 2001-2005 Thomas Graf <tgraf@suug.ch>
    5:  *
    6:  * Permission is hereby granted, free of charge, to any person obtaining a
    7:  * copy of this software and associated documentation files (the "Software"),
    8:  * to deal in the Software without restriction, including without limitation
    9:  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   10:  * and/or sell copies of the Software, and to permit persons to whom the
   11:  * Software is furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included
   14:  * in all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   17:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   21:  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   22:  * DEALINGS IN THE SOFTWARE.
   23:  */
   24: 
   25: #include <bmon/bmon.h>
   26: #include <bmon/node.h>
   27: #include <bmon/output.h>
   28: #include <bmon/graph.h>
   29: #include <bmon/utils.h>
   30: 
   31: static const char *c_path;
   32: static int c_graph_height = 6;
   33: static int c_update_interval = 1;
   34: static int c_rowspan = 1;
   35: static int c_hide_item = 0;
   36: static char *c_title = "Traffic Rate Estimation and Monitoring";
   37: 
   38: static FILE * open_file(const char *p)
   39: {
   40: 	FILE *fd;
   41: 
   42: 	if (!(fd = fopen(p, "w")))
   43: 		quit("fopen(%s) failed: %s\n", p, strerror(errno));
   44: 
   45: 	return fd;
   46: }
   47: 
   48: static void write_css(const char *path)
   49: {
   50:     char ofile[FILENAME_MAX];
   51:     FILE *f;
   52: 
   53: 	snprintf(ofile, sizeof(ofile), "%s/layout.css", path);
   54: 	
   55: 	/* do not overwrite an existing .css */
   56: 	if (!access(ofile, R_OK))
   57: 		return;
   58: 
   59: 	f = open_file(ofile);
   60: 	fprintf(f, 
   61: 		"/*\n" \
   62: 		" * Generated by %s\n" \
   63: 		" */\n" \
   64: 		"\n" \
   65: 		"body {\n" \
   66: 		"	background: #f7f7f7;\n" \
   67: 		"	margin-top: 20px;\n" \
   68: 		"}\n" \
   69: 		"\n" \
   70: 		"p, b, td {\n" \
   71: 		"	color: #000000;\n" \
   72: 		"	font-family: Verdana, Arial, Helvetica, sans-serif;\n" \
   73: 		"	font-size: 10pt;\n" \
   74: 		"}\n" \
   75: 		"\n" \
   76: 		"a:link,a:visited,a:hover {\n" \
   77: 		"  color: #4E7AAF;\n" \
   78: 		"  text-decoration: underline;\n" \
   79: 		"}\n" \
   80: 		"\n" \
   81: 		"p.banner {\n" \
   82: 		"	margin-top: 8px;\n" \
   83: 		"	margin-bottom: 8px;\n" \
   84: 		"	text-align: center;\n" \
   85: 		"	font-size: 18pt;\n" \
   86: 		"	font-weight: bold;\n" \
   87: 		"}\n" \
   88: 		"\n" \
   89: 		"p.node_title {\n" \
   90: 		"	text-align: center;\n" \
   91: 		"	margin: 0pt;\n" \
   92: 		"	margin-bottom: 10px;\n" \
   93: 		"	font-weight: bold;\n" \
   94: 		"	font-size: 18pt;\n" \
   95: 		"}\n" \
   96: 		"\n" \
   97: 		"p.title {\n" \
   98: 		"	margin: 0pt;\n" \
   99: 		"	margin-top: 5px;\n" \
  100: 		"	text-align: center;\n" \
  101: 		"	font-weight: bold;\n" \
  102: 		"	font-size: 14pt;\n" \
  103: 		"}\n" \
  104: 		"\n" \
  105: 		"a.a_node_link:link,a.a_node_link:visited,a.a_node_link:hover {\n" \
  106: 		"	color: #000;\n" \
  107: 		"	font-weight: bold;\n" \
  108: 		"	text-decoration: none;\n" \
  109: 		"}\n" \
  110: 		"\n" \
  111: 		"a.a_node_link:hover {\n" \
  112: 		"	font-weight: bold;\n" \
  113: 		"	text-decoration: underline;\n" \
  114: 		"}\n" \
  115: 		"\n" \
  116: 		"a.a_intf_link:link,a.a_intf_link:visited,a.a_intf_link:hover {\n" \
  117: 		"	color: #000;\n" \
  118: 		"	text-decoration: none;\n" \
  119: 		"}\n" \
  120: 		"\n" \
  121: 		"a.a_intf_link:hover {\n" \
  122: 		"	text-decoration: underline;\n" \
  123: 		"}\n" \
  124: 		"\n" \
  125: 		"p.selection {\n" \
  126: 		"	text-align: center;\n" \
  127: 		"	margin: 0pt;\n" \
  128: 		"}\n" \
  129: 		"\n" \
  130: 		"table.intf_list {\n" \
  131: 		"	border: 1px solid #cdcdcd;\n" \
  132: 		"	width: 100%%;\n" \
  133: 		"	border-spacing: 1px;\n" \
  134: 		"	background: #f8f8f8;\n" \
  135: 		"	margin-bottom: 10px;\n" \
  136: 		"}\n" \
  137: 		"\n" \
  138: 		"tr.intf_list_hdr {\n" \
  139: 		"	font-weight: bold;\n" \
  140: 		"}\n" \
  141: 		"\n" \
  142: 		"th.intf_list_hdr_name {\n" \
  143: 		"	text-align: left;\n" \
  144: 		"	padding-left: 5px;\n" \
  145: 		"}\n" \
  146: 		"\n" \
  147: 		"td.intf_list_nr {\n" \
  148: 		"	border-top: 1px dashed #cdcdcd;\n" \
  149: 		"	text-align: center;\n" \
  150: 		"}\n" \
  151: 		"\n" \
  152: 		"td.intf_list_name {\n" \
  153: 		"	border-top: 1px dashed #cdcdcd;\n" \
  154: 		"	border-left: 1px dashed #cdcdcd;\n" \
  155: 		"	text-align: left;\n" \
  156: 		"	padding-left: 5px;\n" \
  157: 		"}\n" \
  158: 		"\n" \
  159: 		"td.intf_list_rx {\n" \
  160: 		"	border-top: 1px dashed #cdcdcd;\n" \
  161: 		"	border-left: 1px dashed #cdcdcd;\n" \
  162: 		"	text-align: center;\n" \
  163: 		"}\n" \
  164: 		"\n" \
  165: 		"td.intf_list_rxp {\n" \
  166: 		"	border-top: 1px dashed #cdcdcd;\n" \
  167: 		"	border-left: 1px dashed #cdcdcd;\n" \
  168: 		"	text-align: center;\n" \
  169: 		"}\n" \
  170: 		"\n" \
  171: 		"td.intf_list_tx {\n" \
  172: 		"	border-top: 1px dashed #cdcdcd;\n" \
  173: 		"	border-left: 1px dashed #cdcdcd;\n" \
  174: 		"	text-align: center;\n" \
  175: 		"}\n" \
  176: 		"\n" \
  177: 		"td.intf_list_txp {\n" \
  178: 		"	border-top: 1px dashed #cdcdcd;\n" \
  179: 		"	border-left: 1px dashed #cdcdcd;\n" \
  180: 		"	text-align: center;\n" \
  181: 		"}\n" \
  182: 		"	\n" \
  183: 		"table.details {\n" \
  184: 		"	border: 1px solid #cdcdcd;\n" \
  185: 		"	width: 100%%;\n" \
  186: 		"	border-spacing: 1px;\n" \
  187: 		"	background: #f8f8f8;\n" \
  188: 		"	margin-top: 10px;\n" \
  189: 		"}\n" \
  190: 		"\n" \
  191: 		"tr.details_hdr {\n" \
  192: 		"	font-weight: bold;\n" \
  193: 		"}\n" \
  194: 		"\n" \
  195: 		"th.details_hdr_name {\n" \
  196: 		"	text-align: left;\n" \
  197: 		"	padding-left: 20px;\n" \
  198: 		"}\n" \
  199: 		"\n" \
  200: 		"td.details_name {\n" \
  201: 		"	border-top: 1px dashed #cdcdcd;\n" \
  202: 		"	padding-left: 20px;\n" \
  203: 		"}\n" \
  204: 		"\n" \
  205: 		"td.details_rx {\n" \
  206: 		"	border-top: 1px dashed #cdcdcd;\n" \
  207: 		"	border-left: 1px dashed #cdcdcd;\n" \
  208: 		"	text-align: center;\n" \
  209: 		"}\n" \
  210: 		"\n" \
  211: 		"td.details_tx {\n" \
  212: 		"	border-top: 1px dashed #cdcdcd;\n" \
  213: 		"	border-left: 1px dashed #cdcdcd;\n" \
  214: 		"	text-align: center;\n" \
  215: 		"}\n" \
  216: 		"\n" \
  217: 		"table.overall {\n" \
  218: 		"	width: 750px;\n" \
  219: 		"	border-spacing: 0px;\n" \
  220: 		"}\n" \
  221: 		"\n" \
  222: 		"td.header {\n" \
  223: 		"	background: #b8c4db;\n" \
  224: 		"	text-align: center;\n" \
  225: 		"	border: 1px solid #000;\n" \
  226: 		"}\n" \
  227: 		"\n" \
  228: 		"td.left_col {\n" \
  229: 		"	background: #eeeeee;\n" \
  230: 		"	padding-left: 10px;\n" \
  231: 		"	border-left: 1px solid #cdcdcd;\n" \
  232: 		"	border-right: 1px solid #cdcdcd;\n" \
  233: 		"	border-bottom: 1px solid #cdcdcd;\n" \
  234: 		"	vertical-align: top;\n" \
  235: 		"	width: 130px;\n" \
  236: 		"}\n" \
  237: 		"\n" \
  238: 		"td.right_col {\n" \
  239: 		"	background: #fff;\n" \
  240: 		"	padding: 20px;\n" \
  241: 		"	padding-top: 10px;\n" \
  242: 		"	border-bottom: 1px solid #cdcdcd;\n" \
  243: 		"	border-right: 1px solid #cdcdcd;\n" \
  244: 		"	vertical-align: top;\n" \
  245: 		"}\n" \
  246: 		"\n" \
  247: 		"td.fg {\n" \
  248: 		"	background: #6a94b7;\n" \
  249: 		"}\n" \
  250: 		"\n" \
  251: 		"td.noise {\n" \
  252: 		"	background: #9fc5db;\n" \
  253: 		"}\n" \
  254: 		"\n" \
  255: 		"td.bg {\n" \
  256: 		"	background: #eeeeee;\n" \
  257: 		"}\n" \
  258: 		"\n" \
  259: 		"td.unknown {\n" \
  260: 		"	background: #f69191;\n" \
  261: 		"}\n" \
  262: 		"\n" \
  263: 		"table.graph {\n" \
  264: 		"	border: 1px solid #cdcdcd;\n" \
  265: 		"	width: 100%%;\n" \
  266: 		"	border-spacing: 1px;\n" \
  267: 		"	background: #f8f8f8;\n" \
  268: 		"	margin-top: 10px;\n" \
  269: 		"	table-layout: fixed;\n" \
  270: 		"	empty-cells: show;\n" \
  271: 		"	padding-right: 5px;\n" \
  272: 		"	padding-bottom: 5px;\n" \
  273: 		"}\n" \
  274: 		"\n" \
  275: 		"th.graph_hdr {\n" \
  276: 		"}\n" \
  277: 		"\n" \
  278: 		"th.scale_hdr {\n" \
  279: 		"	text-align: right;\n" \
  280: 		"	width: 60px;\n" \
  281: 		"}\n" \
  282: 		"\n" \
  283: 		"td.scale {\n" \
  284: 		"	text-align: right;\n" \
  285: 		"	vertical-align: top;\n" \
  286: 		"}\n" \
  287: 		"\n" \
  288: 		"tr.graph_row {\n" \
  289: 		"	line-height: 7px;\n" \
  290: 		"}\n" \
  291: 		"\n" \
  292: 		"ul.node_list {\n" \
  293: 		"	padding-left: 15px;\n" \
  294: 		"}\n" \
  295: 		"\n" \
  296: 		"ul.node_intf_list {\n" \
  297: 		"	padding-left: 8px;\n" \
  298: 		"}\n" \
  299: 		"\n" \
  300: 		"ul.sub_intf {\n" \
  301: 		"	padding-left: 8px;\n" \
  302: 		"}\n" \
  303: 		"\n" \
  304: 		"tr.legend {\n" \
  305: 		"	line-height: 10px;\n" \
  306: 		"}\n" \
  307: 		"\n" \
  308: 		"td.legend {\n" \
  309: 		"	font-size: 8pt;\n" \
  310: 		"}\n", PACKAGE_STRING);
  311: 	fclose(f);
  312: }
  313: 
  314: struct bxd {
  315: 	FILE *fd;
  316: 	node_t *node;
  317: 	int clevel;
  318: };
  319: 
  320: static void list_add_child(item_t *it, void *arg)
  321: {
  322: 	struct bxd *x = (struct bxd *) arg;
  323: 
  324: 	fprintf(x->fd, "<li><a class=\"a_intf_link\" href=\"%s.%d.bytes.s.html\">%s</a>\n",
  325: 	    x->node->n_name, it->i_index, it->i_name);
  326: 
  327: 	if (it->i_flags & ITEM_FLAG_HAS_CHILDS) {
  328: 		fprintf(x->fd, "<ul class=\"sub_intf\">");
  329: 		foreach_child(x->node, it, list_add_child, arg);
  330: 		fprintf(x->fd, "</ul>\n");
  331: 	}
  332: 
  333: 	fprintf(x->fd, "</li>\n");
  334: }
  335: 
  336: static void list_add_item(item_t *it, void *arg)
  337: {
  338: 	struct bxd *x = (struct bxd *) arg;
  339: 
  340: 	if (it->i_flags & ITEM_FLAG_IS_CHILD)
  341: 		return;
  342: 
  343: 	fprintf(x->fd, "<li><a class=\"a_intf_link\" href=\"%s.%d.bytes.s.html\">%s</a>\n",
  344: 	    x->node->n_name, it->i_index, it->i_name);
  345: 
  346: 	if (it->i_flags & ITEM_FLAG_HAS_CHILDS) {
  347: 		fprintf(x->fd, "<ul class=\"sub_intf\">");
  348: 		foreach_child(x->node, it, list_add_child, arg);
  349: 		fprintf(x->fd, "</ul>\n");
  350: 	}
  351: 
  352: 	fprintf(x->fd, "</li>\n");
  353: }
  354: 
  355: static void list_add(node_t *node, void *arg)
  356: {
  357: 	FILE *fd = (FILE *) arg;
  358: 	struct bxd x = {
  359: 		.fd = fd,
  360: 		.node = node,
  361: 	};
  362: 
  363: 	fprintf(fd, "<li><a class=\"a_node_link\" href=\"%s.html\">%s%s</a>\n",
  364: 		node->n_name, node->n_name, !c_hide_item ? ":" : "");
  365: 
  366: 	if (!c_hide_item) {
  367: 		fprintf(fd, "<ul class=\"node_intf_list\">\n");
  368: 		foreach_item(node, list_add_item, &x);
  369: 		fprintf(fd, "</ul>\n");
  370: 	}
  371: 
  372: 	fprintf(fd, "</li>\n");
  373: }
  374: 
  375: static void write_header(FILE *fd, const char *title)
  376: {
  377: 	fprintf(fd,
  378: 		"<!DOCTYPE html PUBLIC \"-//W3c/DTD XHTML 1.0 Strict//EN\" \n"        \
  379: 		"    \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"        \
  380: 		"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\"\n"          \
  381: 		"       xml:lang=\"en\">\n"                                           \
  382: 		"<head>\n"                                                            \
  383: 		"<title>%s</title>\n"                                                 \
  384: 		"<link rel=\"stylesheet\" type=\"text/css\" href=\"layout.css\" />\n" \
  385: 		"</head>\n"                                                           \
  386: 		"<body>\n"                                                            \
  387: 		"<table class=\"overall\" align=\"center\">\n"                        \
  388: 		"<tr>\n"                                                              \
  389: 		"<td colspan=\"2\" class=\"header\">\n"                               \
  390: 		"<p class=\"banner\">%s</p>\n"                                      \
  391: 		"</td>\n"                                                             \
  392: 		"</tr><tr>\n"                                                         \
  393: 		"<td class=\"left_col\">\n" \
  394: 		"<ul class=\"node_list\">\n",
  395: 		title, c_title);
  396: 
  397: 	foreach_node(list_add, fd);
  398: 
  399: 	fprintf(fd,
  400: 		"</ul></td>\n"                                                         \
  401: 		"<td class=\"right_col\">\n");
  402: }
  403: 
  404: static void write_footer(FILE *fd)
  405: {
  406: 	time_t now = time(0);
  407: 	
  408: 	fprintf(fd,
  409: 		"</td>\n" \
  410: 		"</tr>\n" \
  411: 		"<tr>\n"                                                              \
  412: 		"<td colspan=\"2\" class=\"footer\">\n"                               \
  413: 		"<p class=\"p_footer\">Updated: %s</p>\n"                             \
  414: 		"</td>\n"                                                             \
  415: 		"</tr>\n"                                                         \
  416: 		"</table>\n" \
  417: 		"</body>\n" \
  418: 		"</html>\n",
  419: 		asctime(localtime(&now)));
  420: }
  421: 
  422: struct html_xdata {
  423: 	FILE *fd;
  424: 	node_t *node;
  425: };
  426: 
  427: static void write_interface_entry(FILE *fd, item_t *intf, node_t *node)
  428: {
  429: 	stat_attr_t *bytes, *packets;
  430: 	int i, rxprec, txprec;
  431: 	double rx, tx;
  432: 	char *rx_u, *tx_u;
  433: 	
  434: 	bytes = lookup_attr(intf, intf->i_major_attr);
  435: 	packets = lookup_attr(intf, intf->i_minor_attr);
  436: 
  437: 	if (!bytes || !packets)
  438: 		return;
  439: 
  440: 	rx = cancel_down(attr_get_rx_rate(bytes), bytes->a_unit, &rx_u, &rxprec);
  441: 	tx = cancel_down(attr_get_tx_rate(bytes), bytes->a_unit, &tx_u, &txprec);
  442: 
  443: 	fprintf(fd,
  444: 		"<tr class=\"intf_list_row\">\n" \
  445: 		"<td class=\"intf_list_nr\">%d</td>\n" \
  446: 		"<td class=\"intf_list_name\">",
  447: 		intf->i_index);
  448: 
  449: 	for (i = 0; i < intf->i_level; i++)
  450: 		fprintf(fd, "&nbsp;&nbsp;");
  451: 
  452: 	fprintf(fd,
  453: 		"<a class=\"a_intf\" href=\"%s.%d.bytes.s.html\">%s</a></td>\n" \
  454: 		"<td class=\"intf_list_rx\">%.*f %s</td>\n" \
  455: 		"<td class=\"intf_list_rxp\">%u</td>\n" \
  456: 		"<td class=\"intf_list_tx\">%.*f %s</td>\n" \
  457: 		"<td class=\"intf_list_txp\">%u</td>\n" \
  458: 		"</tr>\n",
  459: 		node->n_name, intf->i_index, intf->i_name,
  460: 		rxprec, rx, rx_u, attr_get_rx_rate(packets),
  461: 		txprec, tx, tx_u, attr_get_tx_rate(packets));
  462: }
  463: 
  464: static void handle_child(item_t *intf, void *arg)
  465: {
  466: 	struct html_xdata *x = arg;
  467: 
  468: 	write_interface_entry(x->fd, intf, x->node);
  469: 	foreach_child(x->node, intf, handle_child, x);
  470: }
  471: 
  472: static void add_to_interace_list(FILE *fd, node_t *node, item_t *intf)
  473: {
  474: 	struct html_xdata x = {
  475: 		.fd = fd,
  476: 		.node = node,
  477: 	};
  478: 
  479: 	if (intf->i_parent)
  480: 		return;
  481: 
  482: 	write_interface_entry(fd, intf, node);
  483: 	foreach_child(node, intf, handle_child, &x);
  484: }
  485: 
  486: static void write_interface_list(FILE *fd, node_t *node)
  487: {
  488: 	int i;
  489: 
  490: 	fprintf(fd,
  491: 		"<p class=\"node_title\">%s</p>\n" \
  492: 		"<table class=\"intf_list\">\n" \
  493: 		"<tr class=\"intf_list_hdr\">\n" \
  494: 		"<th class=\"intf_list_hdr_classx\">#</th>\n" \
  495: 		"<th class=\"intf_list_hdr_name\">Name</th>\n" \
  496: 		"<th class=\"intf_list_hdr_rx\">RX</th>\n" \
  497: 		"<th class=\"intf_list_hdr_rxp\">#</th>\n" \
  498: 		"<th class=\"intf_list_hdr_tx\">TX</th>\n" \
  499: 		"<th class=\"intf_list_hdr_txp\">#</th>\n" \
  500: 		"</tr>", 
  501: 		node->n_name);
  502: 
  503: 	for (i = 0; i < node->n_nitems; i++)
  504: 		if (node->n_items[i].i_name[0])
  505: 			add_to_interace_list(fd, node, &node->n_items[i]);
  506: 
  507: 	fprintf(fd,
  508: 		"</table>\n");
  509: }
  510: 
  511: static void write_graph(FILE *fd, node_t *node, item_t *intf,
  512: 			stat_attr_hist_t *h, hist_elem_t *e, const char *x_unit)
  513: {
  514: 	int i, w, rem;
  515: 	graph_t *g = create_graph(e, c_graph_height, h->a_unit);
  516: 
  517: 	fprintf(fd,
  518: 		"<p class=\"selection\">");
  519: 
  520: 	for (i = 0; i < ATTR_HASH_MAX; i++) {
  521: 		stat_attr_t *a;
  522: 		for (a = intf->i_attrs[i]; a; a = a->a_next) {
  523: 			if (!(a->a_flags & ATTR_FLAG_HISTORY))
  524: 				continue;
  525: 			fprintf(fd,
  526: 				"[<a class=\"a_selection\" href=\"%s.%d.%s.s.html\">%s</a>] ",
  527: 				node->n_name, intf->i_index, type2name(a->a_type),
  528: 				type2desc(a->a_type));
  529: 		}
  530: 	}
  531: 	
  532: 	fprintf(fd,
  533: 		"</p><p class=\"selection\">[");
  534: 
  535: 	if (get_read_interval() != 1.0f)
  536: 		fprintf(fd, 
  537: 			"<a class=\"a_selection\" href=\"%s.%d.%s.r.html\">Read interval</a> ] [",
  538: 				node->n_name, intf->i_index, type2name(h->a_type));
  539: 
  540: 	fprintf(fd, 
  541: 		"<a class=\"a_selection\" href=\"%s.%d.%s.s.html\">Seconds</a>] [" \
  542: 		"<a class=\"a_selection\" href=\"%s.%d.%s.m.html\">Minutes</a>] [" \
  543: 		"<a class=\"a_selection\" href=\"%s.%d.%s.h.html\">Hours</a>] [" \
  544: 		"<a class=\"a_selection\" href=\"%s.%d.%s.d.html\">Days</a>]</p>\n",
  545: 		node->n_name, intf->i_index, type2name(h->a_type),
  546: 		node->n_name, intf->i_index, type2name(h->a_type),
  547: 		node->n_name, intf->i_index, type2name(h->a_type),
  548: 		node->n_name, intf->i_index, type2name(h->a_type));
  549: 	
  550: 
  551: 
  552: 	fprintf(fd, "<table class=\"graph\">\n");
  553: 
  554: 	fprintf(fd, "<tr><th class=\"scale_hdr\">%s</th>" \
  555: 	    "<th class=\"graph_hdr\" colspan=\"61\">RX %s</th></tr>\n",
  556: 	    g->g_tx.t_y_unit, type2desc(h->a_type));
  557: 
  558: 	for (rem = 1, w = (c_graph_height - 1); w >= 0; w--) {
  559: 		char *p;
  560: 		fprintf(fd, "<tr class=\"graph_row\">\n");
  561: 
  562: 		if (--rem == 0) {
  563: 			fprintf(fd, "<td class=\"scale\" rowspan=\"%d\">%8.2f</td>",
  564: 			    c_rowspan, g->g_rx.t_y_scale[w]);
  565: 			rem = c_rowspan;
  566: 		}
  567: 
  568: 		for (p = (char *) (g->g_rx.t_data + (w * (HISTORY_SIZE + 1))); *p; p++) {
  569: 			if (*p == get_fg_char())
  570: 				fprintf(fd, "<td class=\"fg\"></td>");
  571: 			else if (*p == get_noise_char())
  572: 				fprintf(fd, "<td class=\"noise\"></td>");
  573: 			else if (*p == get_unk_char())
  574: 				fprintf(fd, "<td class=\"unknown\"></td>");
  575: 			else
  576: 				fprintf(fd, "<td class=\"bg\"></td>");
  577: 		}
  578: 		fprintf(fd, "<td>&nbsp;</td></tr>");
  579: 	}
  580: 
  581: 	fprintf(fd, "<tr><td>&nbsp;</td>" \
  582: 	    "<td colspan=\"5\">1</td>" \
  583: 	    "<td colspan=\"5\">5</td>" \
  584: 	    "<td colspan=\"5\">10</td>" \
  585: 	    "<td colspan=\"5\">15</td>" \
  586: 	    "<td colspan=\"5\">20</td>" \
  587: 	    "<td colspan=\"5\">25</td>" \
  588: 	    "<td colspan=\"5\">30</td>" \
  589: 	    "<td colspan=\"5\">35</td>" \
  590: 	    "<td colspan=\"5\">40</td>" \
  591: 	    "<td colspan=\"5\">45</td>" \
  592: 	    "<td colspan=\"5\">50</td>" \
  593: 	    "<td colspan=\"5\">55</td>" \
  594: 	    "<td>%s</td></tr>\n" \
  595: 	    "  <tr class=\"legend\">\n" \
  596: 	    "    <td colspan=\"7\"></td>\n" \
  597: 	    "    <td colspan=\"2\" class=\"fg\">&nbsp;</td>\n" \
  598: 	    "    <td colspan=\"15\" class=\"legend\">Consumed</td>\n" \
  599: 	    "    <td colspan=\"2\" class=\"noise\">&nbsp;</td>\n" \
  600: 	    "    <td colspan=\"15\" class=\"legend\">Noise</td>\n" \
  601: 	    "    <td colspan=\"2\" class=\"unknown\">&nbsp;</td>\n" \
  602: 	    "    <td colspan=\"15\" class=\"legend\">No input data</td>\n" \
  603: 	    "    <td colspan=\"4\"></td>\n" \
  604: 	    "  </tr>\n" \
  605: 	    "</table>\n", x_unit);
  606: 	
  607: 	fprintf(fd, "<table class=\"graph\">\n");
  608: 	fprintf(fd, "<tr><th class=\"scale_hdr\">%s</th>" \
  609: 	    "<th class=\"graph_hdr\" colspan=\"61\">TX %s</th></tr>\n",
  610: 	    g->g_tx.t_y_unit, type2desc(h->a_type));
  611: 	
  612: 	for (rem = 1, w = (c_graph_height - 1); w >= 0; w--) {
  613: 		char *p;
  614: 		fprintf(fd, "<tr class=\"graph_row\">\n");
  615: 
  616: 		if (--rem == 0) {
  617: 			fprintf(fd, "<td class=\"scale\" rowspan=\"%d\">%8.2f</td>",
  618: 			    c_rowspan, g->g_tx.t_y_scale[w]);
  619: 			rem = c_rowspan;
  620: 		}
  621: 		for (p = (char *) (g->g_tx.t_data + (w * (HISTORY_SIZE + 1))); *p; p++) {
  622: 			if (*p == get_fg_char())
  623: 				fprintf(fd, "<td class=\"fg\"></td>");
  624: 			else if (*p == get_noise_char())
  625: 				fprintf(fd, "<td class=\"noise\"></td>");
  626: 			else
  627: 				fprintf(fd, "<td class=\"bg\"></td>");
  628: 		}
  629: 		fprintf(fd, "<td>&nbsp;</td></tr>");
  630: 	}
  631: 	fprintf(fd, "<tr><td>&nbsp;</td>" \
  632: 	    "<td colspan=\"5\">1</td>" \
  633: 	    "<td colspan=\"5\">5</td>" \
  634: 	    "<td colspan=\"5\">10</td>" \
  635: 	    "<td colspan=\"5\">15</td>" \
  636: 	    "<td colspan=\"5\">20</td>" \
  637: 	    "<td colspan=\"5\">25</td>" \
  638: 	    "<td colspan=\"5\">30</td>" \
  639: 	    "<td colspan=\"5\">35</td>" \
  640: 	    "<td colspan=\"5\">40</td>" \
  641: 	    "<td colspan=\"5\">45</td>" \
  642: 	    "<td colspan=\"5\">50</td>" \
  643: 	    "<td colspan=\"5\">55</td>" \
  644: 	    "<td>%s</td></tr>\n" \
  645: 	    "  <tr class=\"legend\">\n" \
  646: 	    "    <td colspan=\"7\"></td>\n" \
  647: 	    "    <td colspan=\"2\" class=\"fg\">&nbsp;</td>\n" \
  648: 	    "    <td colspan=\"15\" class=\"legend\">Consumed</td>\n" \
  649: 	    "    <td colspan=\"2\" class=\"noise\">&nbsp;</td>\n" \
  650: 	    "    <td colspan=\"15\" class=\"legend\">Noise</td>\n" \
  651: 	    "    <td colspan=\"2\" class=\"unknown\">&nbsp;</td>\n" \
  652: 	    "    <td colspan=\"15\" class=\"legend\">No input data</td>\n" \
  653: 	    "    <td colspan=\"4\"></td>\n" \
  654: 	    "  </tr>\n" \
  655: 	    "</table>\n", x_unit);
  656: 
  657: 	free_graph(g);
  658: }
  659: 
  660: static void print_attr_detail(stat_attr_t *a, void *arg)
  661: {
  662: 	double rx, tx;
  663: 	char *rx_u, *tx_u;
  664: 	int rxprec, txprec;
  665: 	FILE *fd = (FILE *) arg;
  666: 
  667: 	rx = cancel_down(attr_get_rx(a), a->a_unit, &rx_u, &rxprec);
  668: 	tx = cancel_down(attr_get_tx(a), a->a_unit, &tx_u, &txprec);
  669: 
  670: 	fprintf(fd,
  671: 		"<tr class=\"details\">\n" \
  672: 		"<td class=\"details_name\">%s</td>\n" \
  673: 		"<td class=\"details_rx\">%.*f %s</td>\n" \
  674: 		"<td class=\"details_tx\">%.*f %s</td>\n" \
  675: 		"</tr>\n",
  676: 		type2desc(a->a_type), rxprec, rx, rx_u, txprec, tx, tx_u);
  677: }
  678: 
  679: static void write_details(FILE *fd, item_t *intf)
  680: {
  681: 	
  682: 	fprintf(fd,
  683: 		"<table class=\"details\">\n" \
  684: 		"<tr class=\"details_hdr\">\n" \
  685: 		"<th class=\"details_hdr_name\">Details</th>\n" \
  686: 		"<th class=\"details_hdr_rx\">RX</th>\n" \
  687: 		"<th class=\"details_hdr_tx\">TX</th>\n" \
  688: 		"</tr>\n");
  689: 	
  690: 	foreach_attr(intf, print_attr_detail, (void *) fd);
  691: 
  692: 	fprintf(fd, "</table>\n");
  693: }
  694: 
  695: static void __write_per_item(item_t *intf, node_t *node, stat_attr_hist_t *h,
  696: 			     hist_elem_t *e, char *x_unit)
  697: {
  698: 	char outf[FILENAME_MAX];
  699: 	char title[256];
  700: 	FILE *fd;
  701: 
  702: 	snprintf(outf, sizeof(outf), "%s/%s.%d.%s.%s.html",
  703: 		c_path, node->n_name, intf->i_index, type2name(h->a_type), x_unit);
  704: 	snprintf(title, sizeof(title), "%s on %s - %s/%s",
  705: 	    intf->i_name, node->n_name, type2desc(h->a_type), x_unit);
  706: 	fd = open_file(outf);
  707: 	write_header(fd, title);
  708: 
  709: 	write_interface_list(fd, node);
  710: 	fprintf(fd, "<p class=\"title\">%s</p>\n", intf->i_name);
  711: 	write_graph(fd, node, intf, h, e, x_unit);
  712: 	write_details(fd, intf);
  713: 	
  714: 	write_footer(fd);
  715: 	fclose(fd);
  716: }
  717: 
  718: struct xdata {
  719: 	item_t *i;
  720: 	node_t *n;
  721: };
  722: 
  723: static void write_attr_graph(stat_attr_t *a, void *arg)
  724: {
  725: 	node_t *node = ((struct xdata *) arg)->n;
  726: 	item_t *intf = ((struct xdata *) arg)->i;
  727: 	stat_attr_hist_t *h = (stat_attr_hist_t *) a;
  728: 
  729: 	if (!(a->a_flags & ATTR_FLAG_HISTORY))
  730: 		return;
  731: 
  732: 	if (get_read_interval() != 1.0f)
  733: 		__write_per_item(intf, node, h, &h->a_hist.h_read, "r");
  734: 	__write_per_item(intf, node, h, &h->a_hist.h_sec, "s");
  735: 	__write_per_item(intf, node, h, &h->a_hist.h_min, "m");
  736: 	__write_per_item(intf, node, h, &h->a_hist.h_hour, "h");
  737: 	__write_per_item(intf, node, h, &h->a_hist.h_day, "d");
  738: }
  739: 
  740: static void write_per_item(item_t *intf, void *arg)
  741: {
  742: 	struct xdata x = {
  743: 		.i = intf,
  744: 		.n = (node_t *) arg
  745: 	};
  746: 
  747: 	foreach_attr(intf, &write_attr_graph, &x);
  748: }
  749: 
  750: static void write_per_node(node_t *node, void *arg)
  751: {
  752: 	char outf[FILENAME_MAX];
  753: 	FILE *fd;
  754: 
  755: 	snprintf(outf, sizeof(outf), "%s/%s.html", c_path, node->n_name);
  756: 	fd = open_file(outf);
  757: 	write_header(fd, node->n_name);
  758: 	write_interface_list(fd, node);
  759: 	write_footer(fd);
  760: 	fclose(fd);
  761: 
  762: 	foreach_item(node, write_per_item, (void *) node);
  763: }
  764: 
  765: void html_draw(void)
  766: {
  767: 	static int rem = 1;
  768: 	char outf[FILENAME_MAX];
  769: 	FILE *fd;
  770: 
  771: 	if (--rem)
  772: 		return;
  773: 	else
  774: 		rem = c_update_interval;
  775: 
  776: 	umask(0133);
  777: 	write_css(c_path);
  778: 	
  779: 	foreach_node(write_per_node, NULL);
  780: 
  781: 	snprintf(outf, sizeof(outf), "%s/index.html", c_path);
  782: 	fd = open_file(outf);
  783: 	write_header(fd, c_title);
  784: 	write_footer(fd);
  785: 	fclose(fd);
  786: }
  787: 
  788: static void print_module_help(void)
  789: {
  790: 	printf(
  791: 		"HTML - HTML Output\n" \
  792: 		"\n" \
  793: 		"  Lightweight HTML output with CSS configuration.\n" \
  794: 		"  Author: Thomas Graf <tgraf@suug.ch>\n" \
  795: 		"\n" \
  796: 		"  Options:\n" \
  797: 		"    path=PATH        Output directory\n" \
  798: 		"    interval=SEC     Update interval in seconds (default: 1)\n" \
  799: 		"    rowspan=NUM      Summarize NUM rows into into a single scale step\n" \
  800: 		"    height=NUM       Height of graphical statistics (default: 6)\n" \
  801: 		"    hideitems        Hide interfaces in node list\n" \
  802: 		"    title=STRING     Title of output\n");
  803: }
  804: 
  805: static void html_set_opts(tv_t *attrs)
  806: {
  807: 	while (attrs) {
  808: 		if (!strcasecmp(attrs->type, "path") && attrs->value)
  809: 			c_path = attrs->value;
  810: 		else if (!strcasecmp(attrs->type, "height") && attrs->value)
  811: 			c_graph_height = strtol(attrs->value, NULL, 0);
  812: 		else if (!strcasecmp(attrs->type, "interval") && attrs->value)
  813: 			c_update_interval = strtol(attrs->value, NULL, 0);
  814: 		else if (!strcasecmp(attrs->type, "rowspan") && attrs->value)
  815: 			c_rowspan = strtol(attrs->value, NULL, 0);
  816: 		else if (!strcasecmp(attrs->type, "title") && attrs->value)
  817: 			c_title = attrs->value;
  818: 		else if (!strcasecmp(attrs->type, "hideitems"))
  819: 			c_hide_item = 1;
  820: 		else if (!strcasecmp(attrs->type, "help")) {
  821: 			print_module_help();
  822: 			exit(0);
  823: 		}
  824: 		
  825: 		attrs = attrs->next;
  826: 	}
  827: }
  828: 
  829: static int html_probe(void)
  830: {
  831: 	if (NULL == c_path)
  832: 		quit("You must specify a path (-O html:path=DIR)\n");
  833: 
  834: 	return 1;
  835: }
  836: 
  837: static struct output_module html_ops = {
  838: 	.om_name = "html",
  839: 	.om_draw = html_draw,
  840: 	.om_set_opts = html_set_opts,
  841: 	.om_probe = html_probe,
  842: };
  843: 
  844: static void __init html_init(void)
  845: {
  846: 	register_secondary_output_module(&html_ops);
  847: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>