Annotation of embedaddon/bmon/src/out_html.c, revision 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>