1 /*-
2 * Copyright (c) 2005 Andrey Simonenko
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include "config.h"
28
29 #ifndef lint
30 static const char rcsid[] ATTR_UNUSED =
31 "@(#)$Id: ipastat_st.c,v 1.2 2011/01/23 18:42:35 simon Exp $";
32 #endif /* !lint */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "ipa_mod.h"
39
40 #include "queue.h"
41
42 #include "dlapi.h"
43 #include "confcommon.h"
44 #include "memfunc.h"
45 #include "parser.h"
46
47 #include "ipastat_log.h"
48 #include "ipastat_rules.h"
49 #include "ipastat_st.h"
50 #include "ipastat_main.h"
51
52 const struct st_list *global_st_list; /* global { st_list } */
53
54 signed char debug_st_null; /* debug_st_null parameter. */
55
56 /* Built-in "null" statistics system. */
57 struct st_list st_list_null = STAILQ_HEAD_INITIALIZER(st_list_null);
58
59 /* List of all used "st_list" parameters. */
60 struct st_sets st_sets = SLIST_HEAD_INITIALIZER(st_sets);
61
62 /* List of all statistics modules. */
63 struct st_mod_list st_mod_list;
64
65 /* Current optional statistics name. */
66 struct opt_st *cur_opt_st = NULL;
67
68 /* List of all opt_st structures. */
69 struct opt_st_list opt_st_list = STAILQ_HEAD_INITIALIZER(opt_st_list);
70
71 /*
72 * Find a statistics module by configuration prefix.
73 */
74 struct st_mod *
st_mod_by_prefix(const char * prefix)75 st_mod_by_prefix(const char *prefix)
76 {
77 struct st_mod *st_mod;
78
79 SLIST_FOREACH(st_mod, &st_mod_list, link)
80 if (st_mod->ipa_st_mod->conf_prefix != NULL &&
81 strcmp(st_mod->ipa_st_mod->conf_prefix, prefix) == 0)
82 break;
83 return (st_mod);
84 }
85
86 /*
87 * Find a statistics module by a name.
88 */
89 struct st_mod *
st_mod_by_name(const char * name)90 st_mod_by_name(const char *name)
91 {
92 struct st_mod *st_mod;
93
94 SLIST_FOREACH(st_mod, &st_mod_list, link)
95 if (strcmp(st_mod->ipa_st_mod->st_name, name) == 0)
96 break;
97 return (st_mod);
98 }
99
100 /*
101 * Release memory held by st_set, including struct st_set{}.
102 */
103 static void
free_st_set(struct st_set * set)104 free_st_set(struct st_set *set)
105 {
106 struct st_elem *st, *st_next;
107
108 STAILQ_FOREACH_SAFE(st, &set->list, link, st_next)
109 mem_free(st, m_anon);
110 mem_free(set, m_anon);
111 }
112
113 /*
114 * Release memory held by all st_set.
115 */
116 void
free_st_lists(void)117 free_st_lists(void)
118 {
119 struct st_set *set, *set_next;
120
121 SLIST_FOREACH_SAFE(set, &st_sets, link, set_next)
122 free_st_set(set);
123 }
124
125 /*
126 * Pre-initialize all st_mods.
127 */
128 int
pre_init_st_mods(void)129 pre_init_st_mods(void)
130 {
131 const struct st_mod *st_mod;
132
133 SLIST_FOREACH(st_mod, &st_mod_list, link)
134 if (st_mod->ipa_st_mod->st_pre_init() < 0) {
135 logmsgx(IPA_LOG_ERR, "module %s: st_pre_init failed",
136 st_mod->mod_file);
137 return (-1);
138 }
139 return (0);
140 }
141
142 /*
143 * Initialize all st_mods.
144 */
145 int
init_st_mods(void)146 init_st_mods(void)
147 {
148 const struct st_mod *st_mod;
149
150 SLIST_FOREACH(st_mod, &st_mod_list, link)
151 if (st_mod->ipa_st_mod->st_init() < 0) {
152 logmsgx(IPA_LOG_ERR, "module %s: st_init failed",
153 st_mod->mod_file);
154 return (-1);
155 }
156 return (0);
157 }
158
159 /*
160 * Deinitialize all st_mods.
161 */
162 int
deinit_st_mods(void)163 deinit_st_mods(void)
164 {
165 const struct st_mod *st_mod;
166 int rv;
167
168 rv = 0;
169 SLIST_FOREACH(st_mod, &st_mod_list, link)
170 if (st_mod->ipa_st_mod->st_deinit() < 0) {
171 logmsgx(IPA_LOG_ERR, "module %s: st_deinit failed",
172 st_mod->mod_file);
173 rv = -1;
174 }
175 return (rv);
176 }
177
178 /*
179 * Initialize one rule in statistics systems.
180 */
181 int
st_init_rule(const struct rule * rule)182 st_init_rule(const struct rule *rule)
183 {
184 if (!STAILQ_EMPTY(rule->st_list)) {
185 const struct st_elem *st;
186
187 STAILQ_FOREACH(st, rule->st_list, link) {
188 if (st->ipa_st_mod->st_init_rule == NULL) {
189 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
190 "st_init_rule: module does not support "
191 "rules", st->mod_file, rule->name);
192 return (-1);
193 }
194 if (st->ipa_st_mod->st_init_rule(rule->no,
195 rule->name) < 0) {
196 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
197 "st_init_rule failed", st->mod_file,
198 rule->name);
199 return (-1);
200 }
201 }
202 } else if (debug_st_null)
203 logdbg("rule %s: uses built-in \"null\" statistics system",
204 rule->name);
205 return (0);
206 }
207
208 /*
209 * Deinitialize one rule in statistics systems, which it uses.
210 */
211 int
st_deinit_rule(const struct rule * rule)212 st_deinit_rule(const struct rule *rule)
213 {
214 const struct st_elem *st;
215 int rv;
216
217 rv = 0;
218 STAILQ_FOREACH(st, rule->st_list, link)
219 if (st->ipa_st_mod->st_deinit_rule != NULL &&
220 st->ipa_st_mod->st_deinit_rule(rule->no) < 0) {
221 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
222 "st_deinit_rule failed", st->mod_file, rule->name);
223 rv = -1;
224 }
225 return (rv);
226 }
227
228 int
st_get_rules_list(const struct st_list * st_list,unsigned int * n,struct ipa_entity_desc ** buf_ptr)229 st_get_rules_list(const struct st_list *st_list, unsigned int *n,
230 struct ipa_entity_desc **buf_ptr)
231 {
232 const struct st_elem *st;
233
234 if (STAILQ_EMPTY(st_list)) {
235 /* "null" system: no records and always successful. */
236 *n = 0;
237 *buf_ptr = NULL;
238 return (0);
239 }
240
241 STAILQ_FOREACH(st, st_list, link)
242 if (st->ipa_st_mod->st_get_rules_list != NULL) {
243 if (st->ipa_st_mod->st_get_rules_list(x_pat,
244 x_reg_ptr, m_result, n, buf_ptr) == 0)
245 return (0);
246 logmsgx(IPA_LOG_ERR, "module %s: "
247 "st_get_rules_list failed", st->mod_file);
248 return (-1);
249 }
250 logmsgx(IPA_LOG_ERR, "st_get_rules_list: no statistics system "
251 "is able to return rules list");
252 return (-1);
253 }
254
255 int
st_get_rule_stat(const struct rule * rule,const ipa_tm * tm1,const ipa_tm * tm2,int exact,unsigned int * n,struct ipa_rule_stat ** buf_ptr)256 st_get_rule_stat(const struct rule *rule, const ipa_tm *tm1, const ipa_tm *tm2,
257 int exact, unsigned int *n, struct ipa_rule_stat **buf_ptr)
258 {
259 const struct st_elem *st;
260
261 if (STAILQ_EMPTY(rule->st_list)) {
262 /* "null" system: no records and always successful. */
263 *n = 0;
264 *buf_ptr = NULL;
265 return (0);
266 }
267
268 STAILQ_FOREACH(st, rule->st_list, link)
269 if (st->ipa_st_mod->st_get_rule_stat != NULL) {
270 if (st->ipa_st_mod->st_get_rule_stat(rule->no, tm1,
271 tm2, exact, m_result, n, buf_ptr) == 0)
272 return (0);
273 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
274 "st_get_rule_stat failed", st->mod_file,
275 rule->name);
276 return (-1);
277 }
278 logmsgx(IPA_LOG_ERR, "rule %s: st_get_rule_stat: no statistics "
279 "system is able to return statistics for rule", rule->name);
280 return (-1);
281 }
282
283 int
st_get_rule_info(const struct rule * rule,char ** info_ptr)284 st_get_rule_info(const struct rule *rule, char **info_ptr)
285 {
286 const struct st_elem *st;
287
288 if (STAILQ_EMPTY(rule->st_list)) {
289 /* "null" system: no info. */
290 *info_ptr = NULL;
291 return (0);
292 }
293
294 STAILQ_FOREACH(st, rule->st_list, link)
295 if (st->ipa_st_mod->st_get_rule_info != NULL) {
296 if (st->ipa_st_mod->st_get_rule_info(rule->no,
297 m_result, info_ptr) == 0)
298 return (0);
299 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
300 "st_get_rule_info failed", st->mod_file,
301 rule->name);
302 return (-1);
303 }
304 logmsgx(IPA_LOG_ERR, "rule %s: st_get_rule_info: no statistics "
305 "system is able to return info for rule", rule->name);
306 return (-1);
307 }
308
309 #ifdef WITH_LIMITS
310 /*
311 * Initialize one limit in statistics systems.
312 */
313 int
st_init_limit(const struct rule * rule,const struct limit * limit)314 st_init_limit(const struct rule *rule, const struct limit *limit)
315 {
316 if (!STAILQ_EMPTY(limit->st_list)) {
317 const struct st_elem *st;
318
319 STAILQ_FOREACH(st, limit->st_list, link) {
320 if (st->ipa_st_mod->st_init_limit == NULL) {
321 logmsgx(IPA_LOG_ERR, "module %s: rule %s, "
322 "limit %s: st_init_limit: module does "
323 "not support limits", st->mod_file,
324 rule->name, limit->name);
325 return (-1);
326 }
327 if (st->ipa_st_mod->st_init_limit(rule->no, rule->name,
328 limit->no, limit->name) < 0) {
329 logmsgx(IPA_LOG_ERR, "module %s: rule %s, "
330 "limit %s: st_init_limit failed",
331 st->mod_file, rule->name, limit->name);
332 return (-1);
333 }
334 }
335 } else if (debug_st_null)
336 logdbg("rule %s, limit %s: uses built-in \"null\" "
337 "statistics system", rule->name, limit->name);
338 return (0);
339 }
340
341 /*
342 * Deinitialize one limit in statistics systems, which it uses.
343 */
344 int
st_deinit_limit(const struct rule * rule,const struct limit * limit)345 st_deinit_limit(const struct rule *rule, const struct limit *limit)
346 {
347 const struct st_elem *st;
348 int rv;
349
350 rv = 0;
351 STAILQ_FOREACH(st, limit->st_list, link)
352 if (st->ipa_st_mod->st_deinit_limit != NULL &&
353 st->ipa_st_mod->st_deinit_limit(rule->no, limit->no) < 0) {
354 logmsgx(IPA_LOG_ERR, "module %s: rule %s, limit %s: "
355 "st_deinit_limit failed", st->mod_file, rule->name,
356 limit->name);
357 rv = -1;
358 }
359 return (rv);
360 }
361
362 int
st_get_limits_list(const struct rule * rule,unsigned int * n,struct ipa_entity_desc ** buf_ptr)363 st_get_limits_list(const struct rule *rule, unsigned int *n,
364 struct ipa_entity_desc **buf_ptr)
365 {
366 const struct st_elem *st;
367
368 if (STAILQ_EMPTY(rule->st_list)) {
369 /* "null" system: no records and always successful. */
370 *n = 0;
371 *buf_ptr = NULL;
372 return (0);
373 }
374
375 STAILQ_FOREACH(st, rule->st_list, link)
376 if (st->ipa_st_mod->st_get_limits_list != NULL) {
377 if (st->ipa_st_mod->st_get_limits_list(rule->no,
378 x_pat, x_reg_ptr, m_result, n, buf_ptr) == 0)
379 return (0);
380 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
381 "st_get_limits_list failed", st->mod_file,
382 rule->name);
383 return (-1);
384 }
385 logmsgx(IPA_LOG_ERR, "rule %s: st_get_limits_list: no statistics "
386 "system is able to return list of limits", rule->name);
387 return (-1);
388 }
389
390 int
st_get_limit_stat(const struct rule * rule,const struct limit * limit,const ipa_tm * tm1,const ipa_tm * tm2,unsigned int * n,struct ipa_limit_state ** buf_ptr)391 st_get_limit_stat(const struct rule *rule, const struct limit *limit,
392 const ipa_tm *tm1, const ipa_tm *tm2, unsigned int *n,
393 struct ipa_limit_state **buf_ptr)
394 {
395 const struct st_elem *st;
396
397 if (STAILQ_EMPTY(limit->st_list)) {
398 /* "null" system: no records and always successful. */
399 *n = 0;
400 *buf_ptr = NULL;
401 return (0);
402 }
403
404 STAILQ_FOREACH(st, limit->st_list, link)
405 if (st->ipa_st_mod->st_get_limit_stat != NULL) {
406 if (st->ipa_st_mod->st_get_limit_stat(rule->no,
407 limit->no, tm1, tm2, m_result, n, buf_ptr) == 0)
408 return (0);
409 logmsgx(IPA_LOG_ERR, "module %s: rule %s, limit %s: "
410 "st_get_limit_stat failed", st->mod_file,
411 rule->name, limit->name);
412 return (-1);
413 }
414 logmsgx(IPA_LOG_ERR, "rule %s, limit %s: st_get_limit_stat: "
415 "no statistics system is able to return statistics for limit",
416 rule->name, limit->name);
417 return (-1);
418 }
419
420 int
st_get_limit_info(const struct rule * rule,const struct limit * limit,char ** info_ptr)421 st_get_limit_info(const struct rule *rule, const struct limit *limit,
422 char **info_ptr)
423 {
424 const struct st_elem *st;
425
426 if (STAILQ_EMPTY(limit->st_list)) {
427 /* "null" system: no info. */
428 *info_ptr = NULL;
429 return (0);
430 }
431
432 STAILQ_FOREACH(st, limit->st_list, link)
433 if (st->ipa_st_mod->st_get_limit_info != NULL) {
434 if (st->ipa_st_mod->st_get_limit_info(rule->no,
435 limit->no, m_result, info_ptr) == 0)
436 return (0);
437 logmsgx(IPA_LOG_ERR, "module %s: rule %s, limit %s: "
438 "st_get_limit_info failed", st->mod_file,
439 rule->name, limit->name);
440 return (-1);
441 }
442 logmsgx(IPA_LOG_ERR, "rule %s, limit %s: st_get_limit_info: "
443 "no statistics system is able to return info for limit",
444 rule->name, limit->name);
445 return (-1);
446 }
447 #endif /* WITH_LIMITS */
448
449 #ifdef WITH_THRESHOLDS
450 /*
451 * Initialize one threshold in statistics systems.
452 */
453 int
st_init_threshold(const struct rule * rule,const struct threshold * threshold)454 st_init_threshold(const struct rule *rule, const struct threshold *threshold)
455 {
456 if (!STAILQ_EMPTY(threshold->st_list)) {
457 const struct st_elem *st;
458
459 STAILQ_FOREACH(st, threshold->st_list, link) {
460 if (st->ipa_st_mod->st_init_threshold == NULL) {
461 logmsgx(IPA_LOG_ERR, "module %s: rule %s, "
462 "threshold %s: st_init_threshold: "
463 "module does not support thresholds",
464 st->mod_file, rule->name, threshold->name);
465 return (-1);
466 }
467 if (st->ipa_st_mod->st_init_threshold(rule->no,
468 rule->name, threshold->no, threshold->name) < 0) {
469 logmsgx(IPA_LOG_ERR, "module %s: rule %s, "
470 "threshold %s: st_init_threshold failed",
471 st->mod_file, rule->name, threshold->name);
472 return (-1);
473 }
474 }
475 } else if (debug_st_null)
476 logdbg("rule %s, threshold %s: uses built-in \"null\" "
477 "statistics system", rule->name, threshold->name);
478 return (0);
479 }
480
481 /*
482 * Deinitialize one threshold in statistics systems, which it uses.
483 */
484 int
st_deinit_threshold(const struct rule * rule,const struct threshold * threshold)485 st_deinit_threshold(const struct rule *rule, const struct threshold *threshold)
486 {
487 const struct st_elem *st;
488 int rv;
489
490 rv = 0;
491 STAILQ_FOREACH(st, threshold->st_list, link)
492 if (st->ipa_st_mod->st_deinit_threshold != NULL &&
493 st->ipa_st_mod->st_deinit_threshold(rule->no,
494 threshold->no) < 0) {
495 logmsgx(IPA_LOG_ERR, "module %s: rule %s, "
496 "threshold %s: st_deinit_threshold failed",
497 st->mod_file, rule->name, threshold->name);
498 rv = -1;
499 }
500 return (rv);
501 }
502
503 int
st_get_thresholds_list(const struct rule * rule,unsigned int * n,struct ipa_entity_desc ** buf_ptr)504 st_get_thresholds_list(const struct rule *rule, unsigned int *n,
505 struct ipa_entity_desc **buf_ptr)
506 {
507 const struct st_elem *st;
508
509 if (STAILQ_EMPTY(rule->st_list)) {
510 /* "null" system: no records and always successful. */
511 *n = 0;
512 *buf_ptr = NULL;
513 return (0);
514 }
515
516 STAILQ_FOREACH(st, rule->st_list, link)
517 if (st->ipa_st_mod->st_get_thresholds_list != NULL) {
518 if (st->ipa_st_mod->st_get_thresholds_list(rule->no,
519 x_pat, x_reg_ptr, m_result, n, buf_ptr) == 0)
520 return (0);
521 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
522 "st_get_thresholds_list failed", st->mod_file,
523 rule->name);
524 return (-1);
525 }
526 logmsgx(IPA_LOG_ERR, "rule %s: st_get_thresholds_list: no statistics "
527 "system is able to return list of thresholds", rule->name);
528 return (-1);
529 }
530
531 int
st_get_threshold_stat(const struct rule * rule,const struct threshold * threshold,int * reged,struct ipa_threshold_state * buf)532 st_get_threshold_stat(const struct rule *rule,
533 const struct threshold *threshold, int *reged,
534 struct ipa_threshold_state *buf)
535 {
536 const struct st_elem *st;
537 int rv;
538
539 if (STAILQ_EMPTY(threshold->st_list)) {
540 /* "null" system: no statistics for threshold. */
541 buf->thr = 0;
542 return (0);
543 }
544
545 STAILQ_FOREACH(st, threshold->st_list, link)
546 if (st->ipa_st_mod->st_get_threshold_stat != NULL) {
547 rv = st->ipa_st_mod->st_get_threshold_stat(rule->no,
548 threshold->no, buf);
549 if (rv >= 0) {
550 *reged = (rv > 0);
551 return (0);
552 }
553 logmsgx(IPA_LOG_ERR, "module %s: rule %s, "
554 "threshold %s: st_get_threshold_stat failed",
555 st->mod_file, rule->name, threshold->name);
556 return (-1);
557 }
558 logmsgx(IPA_LOG_ERR, "rule %s, threshold %s: st_get_threshold_stat: "
559 "no statistics system is able to return statistics for threshold",
560 rule->name, threshold->name);
561 return (-1);
562 }
563
564 int
st_get_threshold_info(const struct rule * rule,const struct threshold * threshold,char ** info_ptr)565 st_get_threshold_info(const struct rule *rule,
566 const struct threshold *threshold, char **info_ptr)
567 {
568 const struct st_elem *st;
569
570 if (STAILQ_EMPTY(threshold->st_list)) {
571 /* "null" system: no info. */
572 *info_ptr = NULL;
573 return (0);
574 }
575
576 STAILQ_FOREACH(st, threshold->st_list, link)
577 if (st->ipa_st_mod->st_get_threshold_info != NULL) {
578 if (st->ipa_st_mod->st_get_threshold_info(rule->no,
579 threshold->no, m_result, info_ptr) == 0)
580 return (0);
581 logmsgx(IPA_LOG_ERR, "module %s: rule %s, "
582 "threshold %s: st_get_threshold_info failed",
583 st->mod_file, rule->name, threshold->name);
584 return (-1);
585 }
586 logmsgx(IPA_LOG_ERR, "rule %s, threshold %s: st_get_threshold_info: "
587 "no statistics system is able to return info for threshold",
588 rule->name, threshold->name);
589 return (-1);
590 }
591 #endif /* WITH_THRESHOLDS */
592
593 /*
594 * Add optional statistics name: -q -s name
595 */
596 int
opt_st_add(char * st_names)597 opt_st_add(char *st_names)
598 {
599 struct opt_st *opt_st;
600
601 if (*st_names == '\0') {
602 cur_opt_st = NULL;
603 return (0);
604 }
605 opt_st = mem_malloc(sizeof(*opt_st), m_anon);
606 if (opt_st == NULL) {
607 logmsgx(IPA_LOG_ERR, "opt_st_add: mem_malloc failed");
608 return (-1);
609 }
610 opt_st->st_names = st_names;
611 STAILQ_INSERT_TAIL(&opt_st_list, opt_st, link);
612 cur_opt_st = opt_st;
613 return (0);
614 }
615
616 /*
617 * Parse names of statistics system given in command query.
618 */
619 int
opt_st_parse(void)620 opt_st_parse(void)
621 {
622 const struct st_mod *st_mod;
623 const char *st_name;
624 struct opt_st *opt_st;
625 struct st_set *set;
626 struct st_elem *st;
627 struct st_list *list;
628 char *ptr;
629
630 STAILQ_FOREACH(opt_st, &opt_st_list, link) {
631 set = NULL;
632 list = NULL;
633
634 for (ptr = opt_st->st_names; ptr != NULL;) {
635 st_name = ptr;
636 ptr = strchr(ptr, ' ');
637 if (ptr != NULL) {
638 *ptr++ = '\0';
639 for (; *ptr == ' '; ++ptr)
640 ;
641 }
642 /* Handle "null" statistics system. */
643 if (strcmp(st_name, "null") == 0) {
644 if (list == NULL && ptr == NULL) {
645 list = &st_list_null;
646 continue;
647 }
648 logmsgx(IPA_LOG_ERR, "opt_st_parse: built-in "
649 "statistics system \"null\" cannot be used "
650 "together with another statistics systems");
651 return (-1);
652 }
653
654 st_mod = st_mod_by_name(st_name);
655 if (st_mod == NULL) {
656 logmsgx(IPA_LOG_ERR, "opt_st_parse: "
657 "cannot find module with \"%s\" statistics "
658 "system name", st_name);
659 return (-1);
660 }
661
662 if (set != NULL) {
663 /* We already have set. */
664 STAILQ_FOREACH(st, list, link)
665 if (strcmp(st_name,
666 st->ipa_st_mod->st_name) == 0) {
667 logmsgx(IPA_LOG_ERR,
668 "opt_st_parse: duplicated "
669 "statistics system name "
670 "\"%s\"", st_name);
671 return (-1);
672 }
673 } else {
674 /* Create new set for st_list parameter. */
675 set = mem_malloc(sizeof(*set), m_anon);
676 if (set == NULL) {
677 logmsgx(IPA_LOG_ERR, "opt_st_parse: "
678 "mem_malloc failed");
679 return (-1);
680 }
681 list = &set->list;
682 STAILQ_INIT(list);
683 }
684
685 /* Add new st element to st_list. */
686 st = mem_malloc(sizeof(*st), m_anon);
687 if (st == NULL) {
688 logmsgx(IPA_LOG_ERR, "opt_st_parse: "
689 "mem_malloc failed");
690 return (-1);
691 }
692 st->ipa_st_mod = st_mod->ipa_st_mod;
693 st->mod_file = st_mod->mod_file;
694
695 STAILQ_INSERT_TAIL(list, st, link);
696 }
697
698 opt_st->st_list = list;
699 if (set != NULL)
700 SLIST_INSERT_HEAD(&st_sets, set, link);
701 }
702
703 return (0);
704 }
705
706 /*
707 * Release memory previously allocated by all opt_st_add() calls.
708 */
709 void
opt_st_free(void)710 opt_st_free(void)
711 {
712 struct opt_st *opt_st, *opt_st_next;
713
714 STAILQ_FOREACH_SAFE(opt_st, &opt_st_list, link, opt_st_next)
715 mem_free(opt_st, m_anon);
716 }
717