summaryrefslogtreecommitdiffstats
path: root/src/element.c
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2013-07-05 15:11:46 +0200
committerThomas Graf <tgraf@suug.ch>2013-07-05 15:11:46 +0200
commit3be703f67d34b761725a13b6e58ab22591824bbe (patch)
treee3126790b78f0f9268455d9aac9dfd0e6985b8da /src/element.c
parent924d1e1fb48eb0c1bf0abee3afba005e06368432 (diff)
Initial import
Diffstat (limited to 'src/element.c')
-rw-r--r--src/element.c537
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);
+}