1: /*
2: * src/element.c Elements
3: *
4: * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
5: * Copyright (c) 2013 Red Hat, Inc.
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/conf.h>
28: #include <bmon/element.h>
29: #include <bmon/element_cfg.h>
30: #include <bmon/group.h>
31: #include <bmon/input.h>
32: #include <bmon/utils.h>
33:
34: static LIST_HEAD(allowed);
35: static LIST_HEAD(denied);
36:
37: static int match_mask(const struct policy *p, const char *str)
38: {
39: int i, n;
40: char c;
41:
42: if (!p || !str)
43: return 0;
44:
45: for (i = 0, n = 0; p->p_rule[i] != '\0'; i++) {
46: if (p->p_rule[i] == '*') {
47: c = tolower(p->p_rule[i + 1]);
48:
49: if (c == '\0')
50: return 1;
51:
52: while (tolower(str[n]) != c)
53: if (str[n++] == '\0')
54: return 0;
55: } else if (tolower(p->p_rule[i]) != tolower(str[n++]))
56: return 0;
57: }
58:
59: return str[n] == '\0' ? 1 : 0;
60: }
61:
62: int element_allowed(const char *name, struct element_cfg *cfg)
63: {
64: struct policy *p;
65:
66: if (cfg) {
67: if (cfg->ec_flags & ELEMENT_CFG_HIDE)
68: return 0;
69: else if (cfg->ec_flags & ELEMENT_CFG_SHOW)
70: return 1;
71: }
72:
73: list_for_each_entry(p, &denied, p_list)
74: if (match_mask(p, name))
75: return 0;
76:
77: if (!list_empty(&allowed)) {
78: list_for_each_entry(p, &allowed, p_list)
79: if (match_mask(p, name))
80: return 1;
81:
82: return 0;
83: }
84:
85: return 1;
86: }
87:
88: void element_parse_policy(const char *policy)
89: {
90: char *start, *copy, *save = NULL, *tok;
91: struct policy *p;
92:
93: if (!policy)
94: return;
95:
96: copy = strdup(policy);
97: start = copy;
98:
99: while ((tok = strtok_r(start, ",", &save)) != NULL) {
100: start = NULL;
101:
102: p = xcalloc(1, sizeof(*p));
103:
104: if (*tok == '!') {
105: p->p_rule = strdup(++tok);
106: list_add_tail(&p->p_list, &denied);
107: } else {
108: p->p_rule = strdup(tok);
109: list_add_tail(&p->p_list, &allowed);
110: }
111: }
112:
113: xfree(copy);
114: }
115:
116: struct element *__lookup_element(struct element_group *group, const char *name,
117: uint32_t id, struct element *parent)
118: {
119: struct list_head *list;
120: struct element *e;
121:
122: if (parent)
123: list = &parent->e_childs;
124: else
125: list = &group->g_elements;
126:
127: list_for_each_entry(e, list, e_list)
128: if (!strcmp(name, e->e_name) && e->e_id == id)
129: return e;
130:
131: return NULL;
132: }
133:
134: struct element *element_lookup(struct element_group *group, const char *name,
135: uint32_t id, struct element *parent, int flags)
136: {
137: struct element_cfg *cfg;
138: struct element *e;
139: int i;
140:
141: if (!group)
142: BUG();
143:
144: if ((e = __lookup_element(group, name, id, parent)))
145: return e;
146:
147: if (!(flags & ELEMENT_CREAT))
148: return NULL;
149:
150: cfg = element_cfg_lookup(name);
151: if (!element_allowed(name, cfg))
152: return NULL;
153:
154: DBG("Creating element %d \"%s\"", id, name);
155:
156: e = xcalloc(1, sizeof(*e));
157:
158: init_list_head(&e->e_list);
159: init_list_head(&e->e_childs);
160: init_list_head(&e->e_info_list);
161: init_list_head(&e->e_attr_sorted);
162:
163: for (i = 0; i < ATTR_HASH_SIZE; i++)
164: init_list_head(&e->e_attrhash[i]);
165:
166: e->e_name = strdup(name);
167: e->e_id = id;
168: e->e_parent = parent;
169: e->e_group = group;
170: e->e_lifecycles = get_lifecycles();
171: e->e_flags = ELEMENT_FLAG_CREATED;
172: e->e_cfg = cfg;
173:
174: if (e->e_cfg) {
175: if (e->e_cfg->ec_description)
176: element_update_info(e, "Description",
177: e->e_cfg->ec_description);
178:
179: element_set_rxmax(e, e->e_cfg->ec_rxmax);
180: element_set_txmax(e, e->e_cfg->ec_txmax);
181: }
182:
183: if (parent) {
184: DBG("Attached to parent %d \"%s\"", parent->e_id, parent->e_name);
185: list_add_tail(&e->e_list, &parent->e_childs);
186: } else {
187: DBG("Attached to group %s", group->g_name);
188: list_add_tail(&e->e_list, &group->g_elements);
189: }
190:
191: group->g_nelements++;
192:
193: return e;
194: }
195:
196: void element_free(struct element *e)
197: {
198: struct info *info, *ninfo;
199: struct element *c, *cnext;
200: struct attr *a, *an;
201: int i;
202:
203: if (e->e_group->g_current == e) {
204: element_select_prev();
205: if (e->e_group->g_current == e)
206: e->e_group->g_current = NULL;
207: }
208:
209: list_for_each_entry_safe(c, cnext, &e->e_childs, e_list)
210: element_free(c);
211:
212: list_for_each_entry_safe(info, ninfo, &e->e_info_list, i_list) {
213: xfree(info->i_name);
214: xfree(info->i_value);
215: list_del(&info->i_list);
216: xfree(info);
217: }
218:
219: for (i = 0; i < ATTR_HASH_SIZE; i++)
220: list_for_each_entry_safe(a, an, &e->e_attrhash[i], a_list)
221: attr_free(a);
222:
223: if (e->e_group) {
224: list_del(&e->e_list);
225: e->e_group->g_nelements--;
226: }
227:
228: xfree(e->e_name);
229: xfree(e);
230: }
231:
232: #if 0
233: if (item->i_group->g_selected == item) {
234: if (item_select_prev() == END_OF_LIST) {
235: if (group_select_prev() == END_OF_LIST) {
236: if (node_select_prev() != END_OF_LIST)
237: item_select_last();
238: } else
239: item_select_last();
240: }
241: }
242: #endif
243:
244: #if 0
245:
246: void item_delete(struct item *item)
247: {
248: int m;
249: struct item *child;
250:
251: for (m = 0; m < ATTR_HASH_MAX; m++) {
252: struct attr *a, *next;
253: for (a = item->i_attrs[m]; a; a = next) {
254: next = a->a_next;
255: xfree(a);
256: }
257: }
258:
259: if (item->i_group->g_selected == item) {
260: if (item_select_prev() == END_OF_LIST) {
261: if (group_select_prev() == END_OF_LIST) {
262: if (node_select_prev() != END_OF_LIST)
263: item_select_last();
264: } else
265: item_select_last();
266: }
267: }
268:
269: unlink_item(item);
270: item->i_group->g_nitems--;
271:
272: for (child = item->i_childs; child; child = child->i_next)
273: item_delete(child);
274:
275: if (item->i_path)
276: xfree(item->i_path);
277:
278: xfree(item);
279: }
280:
281: #endif
282:
283: void element_reset_update_flag(struct element_group *g,
284: struct element *e, void *arg)
285: {
286: DBG("Reseting update flag of %s", e->e_name);
287: e->e_flags &= ~ELEMENT_FLAG_UPDATED;
288: }
289:
290: /**
291: * Needs to be called after updating all attributes of an element
292: */
293: void element_notify_update(struct element *e, timestamp_t *ts)
294: {
295: struct attr *a;
296: int i;
297:
298: e->e_flags |= ELEMENT_FLAG_UPDATED;
299:
300: if (ts == NULL)
301: ts = &rtiming.rt_last_read;
302:
303: for (i = 0; i < ATTR_HASH_SIZE; i++)
304: list_for_each_entry(a, &e->e_attrhash[i], a_list)
305: attr_notify_update(a, ts);
306:
307: if (e->e_usage_attr && e->e_cfg &&
308: (a = attr_lookup(e, e->e_usage_attr->ad_id))) {
309: attr_calc_usage(a, &e->e_rx_usage, &e->e_tx_usage,
310: e->e_cfg->ec_rxmax, e->e_cfg->ec_txmax);
311: } else {
312: e->e_rx_usage = FLT_MAX;
313: e->e_tx_usage = FLT_MAX;
314: }
315: }
316:
317: void element_lifesign(struct element *e, int n)
318: {
319: e->e_lifecycles = n * get_lifecycles();
320: }
321:
322: void element_check_if_dead(struct element_group *g,
323: struct element *e, void *arg)
324: {
325: if (--(e->e_lifecycles) <= 0) {
326: element_free(e);
327: DBG("Deleting dead element %s", e->e_name);
328: }
329: }
330:
331: void element_foreach_attr(struct element *e,
332: void (*cb)(struct element *e,
333: struct attr *, void *),
334: void *arg)
335: {
336: struct attr *a;
337:
338: list_for_each_entry(a, &e->e_attr_sorted, a_sort_list)
339: cb(e, a, arg);
340: }
341:
342: int element_set_key_attr(struct element *e, const char *major,
343: const char * minor)
344: {
345: if (!(e->e_key_attr[GT_MAJOR] = attr_def_lookup(major)))
346: return -ENOENT;
347:
348: if (!(e->e_key_attr[GT_MINOR] = attr_def_lookup(minor)))
349: return -ENOENT;
350:
351: return 0;
352: }
353:
354: int element_set_usage_attr(struct element *e, const char *usage)
355: {
356: if (!(e->e_usage_attr = attr_def_lookup(usage)))
357: return -ENOENT;
358:
359: return 0;
360: }
361:
362: struct element *element_current(void)
363: {
364: struct element_group *g;
365:
366: if (!(g = group_current()))
367: return NULL;
368:
369: if (!g->g_current)
370: element_select_first();
371:
372: return g->g_current;
373: }
374:
375: struct element *element_select_first(void)
376: {
377: struct element_group *g;
378:
379: if (!(g = group_current()))
380: return NULL;
381:
382: if (list_empty(&g->g_elements))
383: g->g_current = NULL;
384: else
385: g->g_current = list_first_entry(&g->g_elements,
386: struct element, e_list);
387:
388: return g->g_current;
389: }
390:
391: struct element *element_select_last(void)
392: {
393: struct element_group *g;
394:
395: if (!(g = group_current()))
396: return NULL;
397:
398: if (list_empty(&g->g_elements))
399: g->g_current = NULL;
400: else {
401: struct element *e;
402:
403: e = list_entry(g->g_elements.prev, struct element, e_list);
404:
405: while (!list_empty(&e->e_childs))
406: e = list_entry(e->e_childs.prev, struct element,
407: e_list);
408:
409: g->g_current = e;
410: }
411:
412: return g->g_current;
413: }
414:
415: struct element *element_select_next(void)
416: {
417: struct element_group *g;
418: struct element *e;
419:
420: if (!(g = group_current()))
421: return NULL;
422:
423: if (!(e = g->g_current))
424: return element_select_first();
425:
426: if (!list_empty(&e->e_childs))
427: e = list_first_entry(&e->e_childs, struct element, e_list);
428: else {
429: /*
430: * move upwards until we have no parent or there is a next
431: * entry in the list
432: */
433: while (e->e_parent && e->e_list.next == &e->e_parent->e_childs)
434: e = e->e_parent;
435:
436: if (!e->e_parent && e->e_list.next == &g->g_elements) {
437: group_select_next();
438: return element_select_first();
439: } else
440: e = list_entry(e->e_list.next, struct element, e_list);
441: }
442:
443: g->g_current = e;
444:
445: return e;
446: }
447:
448: struct element *element_select_prev(void)
449: {
450: struct element_group *g;
451: struct element *e;
452:
453: if (!(g = group_current()))
454: return NULL;
455:
456: if (!(e = g->g_current))
457: return element_select_last();
458:
459: if (!e->e_parent && e->e_list.prev == &g->g_elements) {
460: group_select_prev();
461: return element_select_last();
462: }
463:
464: if (e->e_parent && e->e_list.prev == &e->e_parent->e_childs)
465: e = e->e_parent;
466: else {
467: e = list_entry(e->e_list.prev, struct element, e_list);
468:
469: while (!list_empty(&e->e_childs))
470: e = list_entry(e->e_childs.prev, struct element,
471: e_list);
472: }
473:
474: g->g_current = e;
475:
476: return e;
477: }
478:
479: static struct info *element_info_lookup(struct element *e, const char *name)
480: {
481: struct info *i;
482:
483: list_for_each_entry(i, &e->e_info_list, i_list)
484: if (!strcmp(i->i_name, name))
485: return i;
486:
487: return NULL;
488: }
489:
490: void element_update_info(struct element *e, const char *name, const char *value)
491: {
492: struct info *i;
493:
494: if ((i = element_info_lookup(e, name))) {
495: xfree(i->i_value);
496: i->i_value = strdup(value);
497: return;
498: }
499:
500: DBG("Created element info %s (\"%s\")", name, value);
501:
502: i = xcalloc(1, sizeof(*i));
503: i->i_name = strdup(name);
504: i->i_value = strdup(value);
505:
506: e->e_ninfo++;
507:
508: list_add_tail(&i->i_list, &e->e_info_list);
509: }
510:
511: void element_set_txmax(struct element *e, uint64_t max)
512: {
513: char buf[32];
514:
515: if (!e->e_cfg)
516: e->e_cfg = element_cfg_create(e->e_name);
517:
518: if (e->e_cfg->ec_txmax != max)
519: e->e_cfg->ec_txmax = max;
520:
521: unit_bit2str(e->e_cfg->ec_txmax * 8, buf, sizeof(buf));
522: element_update_info(e, "TxMax", buf);
523: }
524:
525: void element_set_rxmax(struct element *e, uint64_t max)
526: {
527: char buf[32];
528:
529: if (!e->e_cfg)
530: e->e_cfg = element_cfg_create(e->e_name);
531:
532: if (e->e_cfg->ec_rxmax != max)
533: e->e_cfg->ec_rxmax = max;
534:
535: unit_bit2str(e->e_cfg->ec_rxmax * 8, buf, sizeof(buf));
536: element_update_info(e, "RxMax", buf);
537: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>