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

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: 
1.1.1.3 ! misho     122:                if (!(a = attr_lookup(e, def->ad_id)))
1.1.1.2   misho     123:                        goto out;
1.1       misho     124: 
1.1.1.2   misho     125:                if (!strncasecmp(type, "rx:", 3)) {
1.1.1.3 ! misho     126:                        snprintf(buf, len, "%" PRIu64, rate_get_total(&a->a_rx_rate));
1.1.1.2   misho     127:                        return buf;
                    128:                } else if (!strncasecmp(type, "tx:", 3)) {
1.1.1.3 ! misho     129:                        snprintf(buf, len, "%" PRIu64, rate_get_total(&a->a_tx_rate));
1.1.1.2   misho     130:                        return buf;
                    131:                } else if (!strncasecmp(type, "rxrate:", 7)) {
                    132:                        snprintf(buf, len, "%.2f", a->a_rx_rate.r_rate);
                    133:                        return buf;
1.1.1.3 ! misho     134:                } else if (!strncasecmp(type, "txrate:", 7)) {
1.1.1.2   misho     135:                        snprintf(buf, len, "%.2f", a->a_tx_rate.r_rate);
                    136:                        return buf;
1.1.1.3 ! misho     137:                }
1.1       misho     138:        }
                    139: 
                    140:        fprintf(stderr, "Unknown field \"%s\"\n", token);
1.1.1.2   misho     141: out:
                    142:        return "unknown";
1.1       misho     143: }
                    144: 
1.1.1.2   misho     145: static void draw_element(struct element_group *g, struct element *e, void *arg)
1.1       misho     146: {
                    147:        int i;
                    148: 
                    149:        for (i = 0; i < token_index; i++) {
1.1.1.2   misho     150:                char buf[128];
                    151:                char *p;
1.1       misho     152: 
1.1.1.2   misho     153:                if (out_tokens[i].ot_type == OT_STRING)
                    154:                        p = out_tokens[i].ot_str;
                    155:                else if (out_tokens[i].ot_type == OT_TOKEN)
                    156:                        p = get_token(g, e, out_tokens[i].ot_str,
                    157:                                      buf, sizeof(buf));
                    158:                else
                    159:                        BUG();
                    160: 
                    161:                if (p)
                    162:                        fprintf(c_fd, "%s", p);
                    163:        }
1.1       misho     164: }
                    165: 
                    166: static void format_draw(void)
                    167: {
1.1.1.2   misho     168:        group_foreach_recursive(draw_element, NULL);
1.1.1.3 ! misho     169:        fflush(stdout);
1.1       misho     170: 
                    171:        if (c_quit_after > 0)
                    172:                if (--c_quit_after == 0)
                    173:                        exit(0);
                    174: }
                    175: 
                    176: static inline void add_token(int type, char *data)
                    177: {
                    178:        if (!out_tokens_size) {
                    179:                out_tokens_size = 32;
                    180:                out_tokens = calloc(out_tokens_size, sizeof(struct out_token));
                    181:                if (out_tokens == NULL)
                    182:                        quit("Cannot allocate out token array\n");
                    183:        }
                    184: 
                    185:        if (out_tokens_size <= token_index) {
                    186:                out_tokens_size += 32;
                    187:                out_tokens = realloc(out_tokens, out_tokens_size * sizeof(struct out_token));
                    188:                if (out_tokens == NULL)
                    189:                        quit("Cannot reallocate out token array\n");
                    190:        }
1.1.1.3 ! misho     191: 
        !           192: 
1.1       misho     193:        out_tokens[token_index].ot_type = type;
                    194:        out_tokens[token_index].ot_str = data;
                    195:        token_index++;
                    196: }
                    197: 
                    198: static int format_probe(void)
                    199: {
                    200:        int new_one = 1;
                    201:        char *p, *e;
                    202: 
                    203:        for (p = c_format; *p; p++) {
                    204:                if (*p == '$') {
                    205:                        char *s = p;
                    206:                        s++;
                    207:                        if (*s == '(') {
                    208:                                s++;
                    209:                                if (!*s)
                    210:                                        goto unexpected_end;
                    211:                                e = strchr(s, ')');
                    212:                                if (e == NULL)
                    213:                                        goto invalid;
                    214: 
                    215:                                *p = '\0';
                    216:                                *e = '\0';
                    217:                                add_token(OT_TOKEN, s);
                    218:                                new_one = 1;
                    219:                                p = e;
                    220:                                continue;
                    221:                        }
                    222:                }
                    223: 
                    224:                if (*p == '\\') {
                    225:                        char *s = p;
                    226:                        s++;
                    227:                        switch (*s) {
                    228:                                case 'n':
                    229:                                        *s = '\n';
                    230:                                        goto finish_escape;
                    231:                                case 't':
                    232:                                        *s = '\t';
                    233:                                        goto finish_escape;
                    234:                                case 'r':
                    235:                                        *s = '\r';
                    236:                                        goto finish_escape;
                    237:                                case 'v':
                    238:                                        *s = '\v';
                    239:                                        goto finish_escape;
                    240:                                case 'b':
                    241:                                        *s = '\b';
                    242:                                        goto finish_escape;
                    243:                                case 'f':
                    244:                                        *s = '\f';
                    245:                                        goto finish_escape;
                    246:                                case 'a':
                    247:                                        *s = '\a';
                    248:                                        goto finish_escape;
                    249:                        }
                    250: 
                    251:                        goto out;
1.1.1.3 ! misho     252: 
1.1       misho     253: finish_escape:
                    254:                        *p = '\0';
                    255:                        add_token(OT_STRING, s);
                    256:                        p = s;
                    257:                        new_one = 0;
                    258:                        continue;
                    259:                }
                    260: 
1.1.1.3 ! misho     261: out:
1.1       misho     262:                if (new_one) {
                    263:                        add_token(OT_STRING, p);
                    264:                        new_one = 0;
                    265:                }
                    266:        }
                    267: 
                    268:        if (c_debug) {
                    269:                int i;
                    270:                for (i = 0; i < token_index; i++)
                    271:                        printf(">>%s<\n", out_tokens[i].ot_str);
                    272:        }
                    273: 
                    274:        return 1;
                    275: 
                    276: unexpected_end:
                    277:        fprintf(stderr, "Unexpected end of format string\n");
                    278:        return 0;
                    279: 
                    280: invalid:
                    281:        fprintf(stderr, "Missing ')' in format string\n");
                    282:        return 0;
                    283: }
                    284: 
                    285: static void print_help(void)
                    286: {
                    287:        printf(
                    288:        "format - Formatable Output\n" \
                    289:        "\n" \
                    290:        "  Formatable ASCII output for scripts. Calls a drawing function for\n" \
                    291:        "  every item per node and outputs according to the specified format\n" \
                    292:        "  string. The format string consists of normal text and placeholders\n" \
                    293:        "  in the form of $(placeholder).\n" \
                    294:        "\n" \
                    295:        "  Author: Thomas Graf <tgraf@suug.ch>\n" \
                    296:        "\n" \
                    297:        "  Options:\n" \
                    298:        "    fmt=FORMAT     Format string\n" \
                    299:        "    stderr         Write to stderr instead of stdout\n" \
1.1.1.2   misho     300:        "    quitafter=NUM  Quit bmon after NUM outputs\n" \
1.1       misho     301:        "\n" \
                    302:        "  Placeholders:\n" \
1.1.1.2   misho     303:        "    group:nelements       Number of elements this group\n" \
                    304:        "         :name            Name of group\n" \
                    305:        "         :title           Title of group\n" \
                    306:        "    element:name          Name of element\n" \
                    307:        "           :desc          Description of element\n" \
                    308:        "           :nattrs        Number of attributes\n" \
                    309:        "           :lifecycles    Number of lifecycles\n" \
                    310:        "           :level         Indentation level\n" \
                    311:        "           :parent        Name of parent element\n" \
                    312:        "           :rxusage       RX usage in percent\n" \
                    313:        "           :txusage       TX usage in percent)\n" \
                    314:        "           :id            ID of element\n" \
                    315:        "           :haschilds     Indicate if element has children (0|1)\n" \
                    316:        "    attr:rx:<name>        RX counter of attribute <name>\n" \
                    317:        "        :tx:<name>        TX counter of attribute <name>\n" \
                    318:        "        :rxrate:<name>    RX rate of attribute <name>\n" \
                    319:        "        :txrate:<name>    TX rate of attribute <name>\n" \
1.1       misho     320:        "\n" \
                    321:        "  Supported Escape Sequences: \\n, \\t, \\r, \\v, \\b, \\f, \\a\n" \
                    322:        "\n" \
                    323:        "  Examples:\n" \
1.1.1.3 ! misho     324:        "    '$(element:name)\\t$(attr:rx:bytes)\\t$(attr:tx:bytes)\\n'\n" \
1.1.1.2   misho     325:        "    lo      12074   12074\n" \
1.1       misho     326:        "\n" \
1.1.1.3 ! misho     327:        "    '$(element:name) $(attr:rxrate:packets) $(attr:txrate:packets)\\n'\n" \
1.1       misho     328:        "    eth0 33 5\n" \
                    329:        "\n" \
1.1.1.3 ! misho     330:        "    'Item: $(element:name)\\nBytes Rate: $(attr:rxrate:bytes)/" \
        !           331:        "$(attr:txrate:bytes)\\nPackets Rate: $(attr:rxrate:packets)/" \
        !           332:        "$(attr:txrate:packets)\\n'\n" \
1.1       misho     333:        "    Item: eth0\n" \
                    334:        "    Bytes Rate: 49130/2119\n" \
                    335:        "    Packets Rate: 40/11\n" \
                    336:        "\n");
                    337: }
                    338: 
1.1.1.2   misho     339: static void format_parse_opt(const char *type, const char *value)
1.1       misho     340: {
1.1.1.2   misho     341:        if (!strcasecmp(type, "stderr"))
                    342:                c_fd = stderr;
                    343:        else if (!strcasecmp(type, "debug"))
                    344:                c_debug = 1;
                    345:        else if (!strcasecmp(type, "fmt")) {
                    346:                if (c_format)
                    347:                        free(c_format);
                    348:                c_format = strdup(value);
                    349:        } else if (!strcasecmp(type, "quitafter") &&
                    350:                               value)
                    351:                c_quit_after = strtol(value, NULL, 0);
                    352:        else if (!strcasecmp(type, "help")) {
                    353:                print_help();
                    354:                exit(0);
1.1       misho     355:        }
                    356: }
                    357: 
1.1.1.2   misho     358: static struct bmon_module format_ops = {
                    359:        .m_name         = "format",
                    360:        .m_do           = format_draw,
                    361:        .m_probe        = format_probe,
                    362:        .m_parse_opt    = format_parse_opt,
1.1       misho     363: };
                    364: 
                    365: static void __init ascii_init(void)
                    366: {
                    367:        c_fd = stdout;
1.1.1.2   misho     368:        c_format = strdup("$(element:name) $(attr:rx:bytes) $(attr:tx:bytes) " \
1.1       misho     369:            "$(attr:rx:packets) $(attr:tx:packets)\\n");
1.1.1.2   misho     370: 
                    371:        output_register(&format_ops);
1.1       misho     372: }

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