Annotation of embedaddon/bmon/src/out_html.c, revision 1.1.1.1

1.1       misho       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>