diff options
author | Thomas Graf <tgraf@suug.ch> | 2013-07-05 15:11:46 +0200 |
---|---|---|
committer | Thomas Graf <tgraf@suug.ch> | 2013-07-05 15:11:46 +0200 |
commit | 3be703f67d34b761725a13b6e58ab22591824bbe (patch) | |
tree | e3126790b78f0f9268455d9aac9dfd0e6985b8da /src/element.c | |
parent | 924d1e1fb48eb0c1bf0abee3afba005e06368432 (diff) |
Initial import
Diffstat (limited to 'src/element.c')
-rw-r--r-- | src/element.c | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/src/element.c b/src/element.c new file mode 100644 index 0000000..d138e36 --- /dev/null +++ b/src/element.c @@ -0,0 +1,537 @@ +/* + * src/element.c Elements + * + * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2013 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <bmon/bmon.h> +#include <bmon/conf.h> +#include <bmon/element.h> +#include <bmon/element_cfg.h> +#include <bmon/group.h> +#include <bmon/input.h> +#include <bmon/utils.h> + +static LIST_HEAD(allowed); +static LIST_HEAD(denied); + +static int match_mask(const struct policy *p, const char *str) +{ + int i, n; + char c; + + if (!p || !str) + return 0; + + for (i = 0, n = 0; p->p_rule[i] != '\0'; i++) { + if (p->p_rule[i] == '*') { + c = tolower(p->p_rule[i + 1]); + + if (c == '\0') + return 1; + + while (tolower(str[n]) != c) + if (str[n++] == '\0') + return 0; + } else if (tolower(p->p_rule[i]) != tolower(str[n++])) + return 0; + } + + return str[n] == '\0' ? 1 : 0; +} + +int element_allowed(const char *name, struct element_cfg *cfg) +{ + struct policy *p; + + if (cfg) { + if (cfg->ec_flags & ELEMENT_CFG_HIDE) + return 0; + else if (cfg->ec_flags & ELEMENT_CFG_SHOW) + return 1; + } + + list_for_each_entry(p, &denied, p_list) + if (match_mask(p, name)) + return 0; + + if (!list_empty(&allowed)) { + list_for_each_entry(p, &allowed, p_list) + if (match_mask(p, name)) + return 1; + + return 0; + } + + return 1; +} + +void element_parse_policy(const char *policy) +{ + char *start, *copy, *save = NULL, *tok; + struct policy *p; + + if (!policy) + return; + + copy = strdup(policy); + start = copy; + + while ((tok = strtok_r(start, ",", &save)) != NULL) { + start = NULL; + + p = xcalloc(1, sizeof(*p)); + + if (*tok == '!') { + p->p_rule = strdup(++tok); + list_add_tail(&p->p_list, &denied); + } else { + p->p_rule = strdup(tok); + list_add_tail(&p->p_list, &allowed); + } + } + + xfree(copy); +} + +struct element *__lookup_element(struct element_group *group, const char *name, + uint32_t id, struct element *parent) +{ + struct list_head *list; + struct element *e; + + if (parent) + list = &parent->e_childs; + else + list = &group->g_elements; + + list_for_each_entry(e, list, e_list) + if (!strcmp(name, e->e_name) && e->e_id == id) + return e; + + return NULL; +} + +struct element *element_lookup(struct element_group *group, const char *name, + uint32_t id, struct element *parent, int flags) +{ + struct element_cfg *cfg; + struct element *e; + int i; + + if (!group) + BUG(); + + if ((e = __lookup_element(group, name, id, parent))) + return e; + + if (!(flags & ELEMENT_CREAT)) + return NULL; + + cfg = element_cfg_lookup(name); + if (!element_allowed(name, cfg)) + return NULL; + + DBG("Creating element %d \"%s\"", id, name); + + e = xcalloc(1, sizeof(*e)); + + init_list_head(&e->e_list); + init_list_head(&e->e_childs); + init_list_head(&e->e_info_list); + init_list_head(&e->e_attr_sorted); + + for (i = 0; i < ATTR_HASH_SIZE; i++) + init_list_head(&e->e_attrhash[i]); + + e->e_name = strdup(name); + e->e_id = id; + e->e_parent = parent; + e->e_group = group; + e->e_lifecycles = get_lifecycles(); + e->e_flags = ELEMENT_FLAG_CREATED; + e->e_cfg = cfg; + + if (e->e_cfg) { + if (e->e_cfg->ec_description) + element_update_info(e, "Description", + e->e_cfg->ec_description); + + element_set_rxmax(e, e->e_cfg->ec_rxmax); + element_set_txmax(e, e->e_cfg->ec_txmax); + } + + if (parent) { + DBG("Attached to parent %d \"%s\"", parent->e_id, parent->e_name); + list_add_tail(&e->e_list, &parent->e_childs); + } else { + DBG("Attached to group %s", group->g_name); + list_add_tail(&e->e_list, &group->g_elements); + } + + group->g_nelements++; + + return e; +} + +void element_free(struct element *e) +{ + struct info *info, *ninfo; + struct element *c, *cnext; + struct attr *a, *an; + int i; + + if (e->e_group->g_current == e) { + element_select_prev(); + if (e->e_group->g_current == e) + e->e_group->g_current = NULL; + } + + list_for_each_entry_safe(c, cnext, &e->e_childs, e_list) + element_free(c); + + list_for_each_entry_safe(info, ninfo, &e->e_info_list, i_list) { + xfree(info->i_name); + xfree(info->i_value); + list_del(&info->i_list); + xfree(info); + } + + for (i = 0; i < ATTR_HASH_SIZE; i++) + list_for_each_entry_safe(a, an, &e->e_attrhash[i], a_list) + attr_free(a); + + if (e->e_group) { + list_del(&e->e_list); + e->e_group->g_nelements--; + } + + xfree(e->e_name); + xfree(e); +} + +#if 0 + if (item->i_group->g_selected == item) { + if (item_select_prev() == END_OF_LIST) { + if (group_select_prev() == END_OF_LIST) { + if (node_select_prev() != END_OF_LIST) + item_select_last(); + } else + item_select_last(); + } + } +#endif + +#if 0 + +void item_delete(struct item *item) +{ + int m; + struct item *child; + + for (m = 0; m < ATTR_HASH_MAX; m++) { + struct attr *a, *next; + for (a = item->i_attrs[m]; a; a = next) { + next = a->a_next; + xfree(a); + } + } + + if (item->i_group->g_selected == item) { + if (item_select_prev() == END_OF_LIST) { + if (group_select_prev() == END_OF_LIST) { + if (node_select_prev() != END_OF_LIST) + item_select_last(); + } else + item_select_last(); + } + } + + unlink_item(item); + item->i_group->g_nitems--; + + for (child = item->i_childs; child; child = child->i_next) + item_delete(child); + + if (item->i_path) + xfree(item->i_path); + + xfree(item); +} + +#endif + +void element_reset_update_flag(struct element_group *g, + struct element *e, void *arg) +{ + DBG("Reseting update flag of %s", e->e_name); + e->e_flags &= ~ELEMENT_FLAG_UPDATED; +} + +/** + * Needs to be called after updating all attributes of an element + */ +void element_notify_update(struct element *e, timestamp_t *ts) +{ + struct attr *a; + int i; + + e->e_flags |= ELEMENT_FLAG_UPDATED; + + if (ts == NULL) + ts = &rtiming.rt_last_read; + + for (i = 0; i < ATTR_HASH_SIZE; i++) + list_for_each_entry(a, &e->e_attrhash[i], a_list) + attr_notify_update(a, ts); + + if (e->e_usage_attr && e->e_cfg && + (a = attr_lookup(e, e->e_usage_attr->ad_id))) { + attr_calc_usage(a, &e->e_rx_usage, &e->e_tx_usage, + e->e_cfg->ec_rxmax, e->e_cfg->ec_txmax); + } else { + e->e_rx_usage = FLT_MAX; + e->e_tx_usage = FLT_MAX; + } +} + +void element_lifesign(struct element *e, int n) +{ + e->e_lifecycles = n * get_lifecycles(); +} + +void element_check_if_dead(struct element_group *g, + struct element *e, void *arg) +{ + if (--(e->e_lifecycles) <= 0) { + element_free(e); + DBG("Deleting dead element %s", e->e_name); + } +} + +void element_foreach_attr(struct element *e, + void (*cb)(struct element *e, + struct attr *, void *), + void *arg) +{ + struct attr *a; + + list_for_each_entry(a, &e->e_attr_sorted, a_sort_list) + cb(e, a, arg); +} + +int element_set_key_attr(struct element *e, const char *major, + const char * minor) +{ + if (!(e->e_key_attr[GT_MAJOR] = attr_def_lookup(major))) + return -ENOENT; + + if (!(e->e_key_attr[GT_MINOR] = attr_def_lookup(minor))) + return -ENOENT; + + return 0; +} + +int element_set_usage_attr(struct element *e, const char *usage) +{ + if (!(e->e_usage_attr = attr_def_lookup(usage))) + return -ENOENT; + + return 0; +} + +struct element *element_current(void) +{ + struct element_group *g; + + if (!(g = group_current())) + return NULL; + + if (!g->g_current) + element_select_first(); + + return g->g_current; +} + +struct element *element_select_first(void) +{ + struct element_group *g; + + if (!(g = group_current())) + return NULL; + + if (list_empty(&g->g_elements)) + g->g_current = NULL; + else + g->g_current = list_first_entry(&g->g_elements, + struct element, e_list); + + return g->g_current; +} + +struct element *element_select_last(void) +{ + struct element_group *g; + + if (!(g = group_current())) + return NULL; + + if (list_empty(&g->g_elements)) + g->g_current = NULL; + else { + struct element *e; + + e = list_entry(g->g_elements.prev, struct element, e_list); + + while (!list_empty(&e->e_childs)) + e = list_entry(e->e_childs.prev, struct element, + e_list); + + g->g_current = e; + } + + return g->g_current; +} + +struct element *element_select_next(void) +{ + struct element_group *g; + struct element *e; + + if (!(g = group_current())) + return NULL; + + if (!(e = g->g_current)) + return element_select_first(); + + if (!list_empty(&e->e_childs)) + e = list_first_entry(&e->e_childs, struct element, e_list); + else { + /* + * move upwards until we have no parent or there is a next + * entry in the list + */ + while (e->e_parent && e->e_list.next == &e->e_parent->e_childs) + e = e->e_parent; + + if (!e->e_parent && e->e_list.next == &g->g_elements) { + group_select_next(); + return element_select_first(); + } else + e = list_entry(e->e_list.next, struct element, e_list); + } + + g->g_current = e; + + return e; +} + +struct element *element_select_prev(void) +{ + struct element_group *g; + struct element *e; + + if (!(g = group_current())) + return NULL; + + if (!(e = g->g_current)) + return element_select_last(); + + if (!e->e_parent && e->e_list.prev == &g->g_elements) { + group_select_prev(); + return element_select_last(); + } + + if (e->e_parent && e->e_list.prev == &e->e_parent->e_childs) + e = e->e_parent; + else { + e = list_entry(e->e_list.prev, struct element, e_list); + + while (!list_empty(&e->e_childs)) + e = list_entry(e->e_childs.prev, struct element, + e_list); + } + + g->g_current = e; + + return e; +} + +static struct info *element_info_lookup(struct element *e, const char *name) +{ + struct info *i; + + list_for_each_entry(i, &e->e_info_list, i_list) + if (!strcmp(i->i_name, name)) + return i; + + return NULL; +} + +void element_update_info(struct element *e, const char *name, const char *value) +{ + struct info *i; + + if ((i = element_info_lookup(e, name))) { + xfree(i->i_value); + i->i_value = strdup(value); + return; + } + + DBG("Created element info %s (\"%s\")", name, value); + + i = xcalloc(1, sizeof(*i)); + i->i_name = strdup(name); + i->i_value = strdup(value); + + e->e_ninfo++; + + list_add_tail(&i->i_list, &e->e_info_list); +} + +void element_set_txmax(struct element *e, uint64_t max) +{ + char buf[32]; + + if (!e->e_cfg) + e->e_cfg = element_cfg_create(e->e_name); + + if (e->e_cfg->ec_txmax != max) + e->e_cfg->ec_txmax = max; + + unit_bit2str(e->e_cfg->ec_txmax * 8, buf, sizeof(buf)); + element_update_info(e, "TxMax", buf); +} + +void element_set_rxmax(struct element *e, uint64_t max) +{ + char buf[32]; + + if (!e->e_cfg) + e->e_cfg = element_cfg_create(e->e_name); + + if (e->e_cfg->ec_rxmax != max) + e->e_cfg->ec_rxmax = max; + + unit_bit2str(e->e_cfg->ec_rxmax * 8, buf, sizeof(buf)); + element_update_info(e, "RxMax", buf); +} |