Annotation of embedaddon/bmon/src/out_format.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * out_format.c                Formatted Output
                      3:  *
1.1.1.2 ! misho       4:  * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
        !             5:  * Copyright (c) 2013 Red Hat, Inc.
1.1       misho       6:  *
                      7:  * Permission is hereby granted, free of charge, to any person obtaining a
                      8:  * copy of this software and associated documentation files (the "Software"),
                      9:  * to deal in the Software without restriction, including without limitation
                     10:  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
                     11:  * and/or sell copies of the Software, and to permit persons to whom the
                     12:  * Software is furnished to do so, subject to the following conditions:
                     13:  *
                     14:  * The above copyright notice and this permission notice shall be included
                     15:  * in all copies or substantial portions of the Software.
                     16:  *
                     17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
                     18:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
                     22:  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
                     23:  * DEALINGS IN THE SOFTWARE.
                     24:  */
                     25: 
                     26: #include <bmon/bmon.h>
                     27: #include <bmon/graph.h>
                     28: #include <bmon/conf.h>
                     29: #include <bmon/output.h>
1.1.1.2 ! misho      30: #include <bmon/group.h>
        !            31: #include <bmon/element.h>
1.1       misho      32: #include <bmon/input.h>
                     33: #include <bmon/utils.h>
1.1.1.2 ! misho      34: #include <bmon/attr.h>
1.1       misho      35: 
                     36: static int c_quit_after = -1;
                     37: static char *c_format;
                     38: static int c_debug = 0;
                     39: static FILE *c_fd;
                     40: 
                     41: enum {
                     42:        OT_STRING,
                     43:        OT_TOKEN
                     44: };
                     45: 
                     46: static struct out_token {
                     47:        int ot_type;
                     48:        char *ot_str;
                     49: } *out_tokens;
                     50: 
                     51: static int token_index;
                     52: static int out_tokens_size;
                     53: 
1.1.1.2 ! misho      54: static char *get_token(struct element_group *g, struct element *e,
        !            55:                       const char *token, char *buf, size_t len)
1.1       misho      56: {
1.1.1.2 ! misho      57:        if (!strncasecmp(token, "group:", 6)) {
        !            58:                const char *n = token + 6;
1.1       misho      59: 
1.1.1.2 ! misho      60:                if (!strcasecmp(n, "nelements")) {
        !            61:                        snprintf(buf, len, "%u", g->g_nelements);
        !            62:                        return buf;
        !            63:                } else if (!strcasecmp(n, "name"))
        !            64:                        return g->g_name;
        !            65:                else if (!strcasecmp(n, "title"))
        !            66:                        return g->g_hdr->gh_title;
        !            67: 
        !            68:        } else if (!strncasecmp(token, "element:", 8)) {
        !            69:                const char *n = token + 8;
        !            70: 
        !            71:                if (!strcasecmp(n, "name"))
        !            72:                        return e->e_name;
        !            73:                else if (!strcasecmp(n, "description"))
        !            74:                        return e->e_description;
        !            75:                else if (!strcasecmp(n, "nattrs")) {
        !            76:                        snprintf(buf, len, "%u", e->e_nattrs);
        !            77:                        return buf;
        !            78:                } else if (!strcasecmp(n, "lifecycles")) {
        !            79:                        snprintf(buf, len, "%u", e->e_lifecycles);
        !            80:                        return buf;
        !            81:                } else if (!strcasecmp(n, "level")) {
        !            82:                        snprintf(buf, len, "%u", e->e_level);
        !            83:                        return buf;
        !            84:                } else if (!strcasecmp(n, "parent"))
        !            85:                        return e->e_parent ? e->e_parent->e_name : "";
        !            86:                else if (!strcasecmp(n, "id")) {
        !            87:                        snprintf(buf, len, "%u", e->e_id);
        !            88:                        return buf;
        !            89:                } else if (!strcasecmp(n, "rxusage")) {
        !            90:                        snprintf(buf, len, "%2.0f",
        !            91:                                e->e_rx_usage == FLT_MAX ? e->e_rx_usage : 0.0f);
        !            92:                        return buf;
        !            93:                } else if (!strcasecmp(n, "txusage")) {
        !            94:                        snprintf(buf, len, "%2.0f",
        !            95:                                e->e_tx_usage == FLT_MAX ? e->e_tx_usage : 0.0f);
        !            96:                        return buf;
        !            97:                } else if (!strcasecmp(n, "haschilds")) {
        !            98:                        snprintf(buf, len, "%u",
        !            99:                                list_empty(&e->e_childs) ? 0 : 1);
        !           100:                        return buf;
        !           101:                }
        !           102:        } else if (!strncasecmp(token, "attr:", 5)) {
        !           103:                const char *type = token + 5;
        !           104:                char *name = strchr(type, ':');
        !           105:                struct attr_def *def;
        !           106:                struct attr *a;
        !           107: 
        !           108:                if (!name) {
1.1       misho     109:                        fprintf(stderr, "Invalid attribute field \"%s\"\n",
1.1.1.2 ! misho     110:                                type);
        !           111:                        goto out;
1.1       misho     112:                }
                    113: 
1.1.1.2 ! misho     114:                name++;
        !           115: 
        !           116:                def = attr_def_lookup(name);
        !           117:                if (!def) {
        !           118:                        fprintf(stderr, "Undefined attribute \"%s\"\n", name);
        !           119:                        goto out;
        !           120:                }
        !           121: 
        !           122:                if (!(a = attr_lookup(e, def->ad_id))) {
        !           123:                        fprintf(stderr, "Unable to find attribute %u (%s)\n",
        !           124:                                def->ad_id, name);
        !           125:                        goto out;
1.1       misho     126:                }
                    127: 
1.1.1.2 ! misho     128:                if (!strncasecmp(type, "rx:", 3)) {
        !           129:                        snprintf(buf, len, "%llu", a->a_rx_rate.r_total);
        !           130:                        return buf;
        !           131:                } else if (!strncasecmp(type, "tx:", 3)) {
        !           132:                        snprintf(buf, len, "%llu", a->a_tx_rate.r_total);
        !           133:                        return buf;
        !           134:                } else if (!strncasecmp(type, "rxrate:", 7)) {
        !           135:                        snprintf(buf, len, "%.2f", a->a_rx_rate.r_rate);
        !           136:                        return buf;
        !           137:                } else if (!strncasecmp(token+5, "txrate:", 7))
        !           138:                        snprintf(buf, len, "%.2f", a->a_tx_rate.r_rate);
        !           139:                        return buf;
1.1       misho     140:        }
                    141: 
                    142:        fprintf(stderr, "Unknown field \"%s\"\n", token);
1.1.1.2 ! misho     143: out:
        !           144:        return "unknown";
1.1       misho     145: }
                    146: 
1.1.1.2 ! misho     147: static void draw_element(struct element_group *g, struct element *e, void *arg)
1.1       misho     148: {
                    149:        int i;
                    150: 
                    151:        for (i = 0; i < token_index; i++) {
1.1.1.2 ! misho     152:                char buf[128];
        !           153:                char *p;
1.1       misho     154: 
1.1.1.2 ! misho     155:                if (out_tokens[i].ot_type == OT_STRING)
        !           156:                        p = out_tokens[i].ot_str;
        !           157:                else if (out_tokens[i].ot_type == OT_TOKEN)
        !           158:                        p = get_token(g, e, out_tokens[i].ot_str,
        !           159:                                      buf, sizeof(buf));
        !           160:                else
        !           161:                        BUG();
        !           162: 
        !           163:                if (p)
        !           164:                        fprintf(c_fd, "%s", p);
        !           165:        }
1.1       misho     166: }
                    167: 
                    168: static void format_draw(void)
                    169: {
1.1.1.2 ! misho     170:        group_foreach_recursive(draw_element, NULL);
1.1       misho     171: 
                    172:        if (c_quit_after > 0)
                    173:                if (--c_quit_after == 0)
                    174:                        exit(0);
                    175: }
                    176: 
                    177: static inline void add_token(int type, char *data)
                    178: {
                    179:        if (!out_tokens_size) {
                    180:                out_tokens_size = 32;
                    181:                out_tokens = calloc(out_tokens_size, sizeof(struct out_token));
                    182:                if (out_tokens == NULL)
                    183:                        quit("Cannot allocate out token array\n");
                    184:        }
                    185: 
                    186:        if (out_tokens_size <= token_index) {
                    187:                out_tokens_size += 32;
                    188:                out_tokens = realloc(out_tokens, out_tokens_size * sizeof(struct out_token));
                    189:                if (out_tokens == NULL)
                    190:                        quit("Cannot reallocate out token array\n");
                    191:        }
                    192:                
                    193:                
                    194:        out_tokens[token_index].ot_type = type;
                    195:        out_tokens[token_index].ot_str = data;
                    196:        token_index++;
                    197: }
                    198: 
                    199: static int format_probe(void)
                    200: {
                    201:        int new_one = 1;
                    202:        char *p, *e;
                    203: 
                    204:        for (p = c_format; *p; p++) {
                    205:                if (*p == '$') {
                    206:                        char *s = p;
                    207:                        s++;
                    208:                        if (*s == '(') {
                    209:                                s++;
                    210:                                if (!*s)
                    211:                                        goto unexpected_end;
                    212:                                e = strchr(s, ')');
                    213:                                if (e == NULL)
                    214:                                        goto invalid;
                    215: 
                    216:                                *p = '\0';
                    217:                                *e = '\0';
                    218:                                add_token(OT_TOKEN, s);
                    219:                                new_one = 1;
                    220:                                p = e;
                    221:                                continue;
                    222:                        }
                    223:                }
                    224: 
                    225:                if (*p == '\\') {
                    226:                        char *s = p;
                    227:                        s++;
                    228:                        switch (*s) {
                    229:                                case 'n':
                    230:                                        *s = '\n';
                    231:                                        goto finish_escape;
                    232:                                case 't':
                    233:                                        *s = '\t';
                    234:                                        goto finish_escape;
                    235:                                case 'r':
                    236:                                        *s = '\r';
                    237:                                        goto finish_escape;
                    238:                                case 'v':
                    239:                                        *s = '\v';
                    240:                                        goto finish_escape;
                    241:                                case 'b':
                    242:                                        *s = '\b';
                    243:                                        goto finish_escape;
                    244:                                case 'f':
                    245:                                        *s = '\f';
                    246:                                        goto finish_escape;
                    247:                                case 'a':
                    248:                                        *s = '\a';
                    249:                                        goto finish_escape;
                    250:                        }
                    251: 
                    252:                        goto out;
                    253:                
                    254: finish_escape:
                    255:                        *p = '\0';
                    256:                        add_token(OT_STRING, s);
                    257:                        p = s;
                    258:                        new_one = 0;
                    259:                        continue;
                    260:                }
                    261: 
                    262: out:   
                    263:                if (new_one) {
                    264:                        add_token(OT_STRING, p);
                    265:                        new_one = 0;
                    266:                }
                    267:        }
                    268: 
                    269:        if (c_debug) {
                    270:                int i;
                    271:                for (i = 0; i < token_index; i++)
                    272:                        printf(">>%s<\n", out_tokens[i].ot_str);
                    273:        }
                    274: 
                    275:        return 1;
                    276: 
                    277: unexpected_end:
                    278:        fprintf(stderr, "Unexpected end of format string\n");
                    279:        return 0;
                    280: 
                    281: invalid:
                    282:        fprintf(stderr, "Missing ')' in format string\n");
                    283:        return 0;
                    284: }
                    285: 
                    286: static void print_help(void)
                    287: {
                    288:        printf(
                    289:        "format - Formatable Output\n" \
                    290:        "\n" \
                    291:        "  Formatable ASCII output for scripts. Calls a drawing function for\n" \
                    292:        "  every item per node and outputs according to the specified format\n" \
                    293:        "  string. The format string consists of normal text and placeholders\n" \
                    294:        "  in the form of $(placeholder).\n" \
                    295:        "\n" \
                    296:        "  Author: Thomas Graf <tgraf@suug.ch>\n" \
                    297:        "\n" \
                    298:        "  Options:\n" \
                    299:        "    fmt=FORMAT     Format string\n" \
                    300:        "    stderr         Write to stderr instead of stdout\n" \
1.1.1.2 ! misho     301:        "    quitafter=NUM  Quit bmon after NUM outputs\n" \
1.1       misho     302:        "\n" \
                    303:        "  Placeholders:\n" \
1.1.1.2 ! misho     304:        "    group:nelements       Number of elements this group\n" \
        !           305:        "         :name            Name of group\n" \
        !           306:        "         :title           Title of group\n" \
        !           307:        "    element:name          Name of element\n" \
        !           308:        "           :desc          Description of element\n" \
        !           309:        "           :nattrs        Number of attributes\n" \
        !           310:        "           :lifecycles    Number of lifecycles\n" \
        !           311:        "           :level         Indentation level\n" \
        !           312:        "           :parent        Name of parent element\n" \
        !           313:        "           :rxusage       RX usage in percent\n" \
        !           314:        "           :txusage       TX usage in percent)\n" \
        !           315:        "           :id            ID of element\n" \
        !           316:        "           :haschilds     Indicate if element has children (0|1)\n" \
        !           317:        "    attr:rx:<name>        RX counter of attribute <name>\n" \
        !           318:        "        :tx:<name>        TX counter of attribute <name>\n" \
        !           319:        "        :rxrate:<name>    RX rate of attribute <name>\n" \
        !           320:        "        :txrate:<name>    TX rate of attribute <name>\n" \
1.1       misho     321:        "\n" \
                    322:        "  Supported Escape Sequences: \\n, \\t, \\r, \\v, \\b, \\f, \\a\n" \
                    323:        "\n" \
                    324:        "  Examples:\n" \
1.1.1.2 ! misho     325:        "    \"$(element:name)\\t$(attr:rx:bytes)\\t$(attr:tx:bytes)\\n\"\n" \
        !           326:        "    lo      12074   12074\n" \
1.1       misho     327:        "\n" \
1.1.1.2 ! misho     328:        "    \"$(element:name) $(attr:rxrate:packets) $(attr:txrate:packets)\\n\"\n" \
1.1       misho     329:        "    eth0 33 5\n" \
                    330:        "\n" \
1.1.1.2 ! misho     331:        "    \"Element: $(element:name)\\nBytes Rate: \" \\\n" \
1.1       misho     332:        "        \"$(attr:rxrate:bytes)/$(attr:txrate:bytes)\\nPackets Rate: \" \\\n" \
                    333:        "        \"$(attr:rxrate:packets)/$(attr:txrate:packets)\\n\"\n" \
                    334:        "    Item: eth0\n" \
                    335:        "    Bytes Rate: 49130/2119\n" \
                    336:        "    Packets Rate: 40/11\n" \
                    337:        "\n");
                    338: }
                    339: 
1.1.1.2 ! misho     340: static void format_parse_opt(const char *type, const char *value)
1.1       misho     341: {
1.1.1.2 ! misho     342:        if (!strcasecmp(type, "stderr"))
        !           343:                c_fd = stderr;
        !           344:        else if (!strcasecmp(type, "debug"))
        !           345:                c_debug = 1;
        !           346:        else if (!strcasecmp(type, "fmt")) {
        !           347:                if (c_format)
        !           348:                        free(c_format);
        !           349:                c_format = strdup(value);
        !           350:        } else if (!strcasecmp(type, "quitafter") &&
        !           351:                               value)
        !           352:                c_quit_after = strtol(value, NULL, 0);
        !           353:        else if (!strcasecmp(type, "help")) {
        !           354:                print_help();
        !           355:                exit(0);
1.1       misho     356:        }
                    357: }
                    358: 
1.1.1.2 ! misho     359: static struct bmon_module format_ops = {
        !           360:        .m_name         = "format",
        !           361:        .m_do           = format_draw,
        !           362:        .m_probe        = format_probe,
        !           363:        .m_parse_opt    = format_parse_opt,
1.1       misho     364: };
                    365: 
                    366: static void __init ascii_init(void)
                    367: {
                    368:        c_fd = stdout;
1.1.1.2 ! misho     369:        c_format = strdup("$(element:name) $(attr:rx:bytes) $(attr:tx:bytes) " \
1.1       misho     370:            "$(attr:rx:packets) $(attr:tx:packets)\\n");
1.1.1.2 ! misho     371: 
        !           372:        output_register(&format_ops);
1.1       misho     373: }

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