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_main.c,v 1.2.2.1 2012/07/09 20:28:19 simon Exp $";
32 #endif /* !lint */
33
34 #include <sys/types.h>
35
36 #include <regex.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "ipa_mod.h"
43
44 #include "queue.h"
45
46 #include "dlapi.h"
47 #include "confcommon.h"
48 #include "memfunc.h"
49
50 #include "ipastat_conf.h"
51 #include "ipastat_log.h"
52 #include "ipastat_main.h"
53 #include "ipastat_rules.h"
54 #include "ipastat_time.h"
55 #include "ipastat_st.h"
56
57 const char *x_pat = NULL; /* -q -x pattern */
58 regex_t x_reg; /* Compiled x_pat. */
59 regex_t *x_reg_ptr = NULL; /* NULL or &x_reg. */
60
61 unsigned int a_flag = A_FLAG_ABSENT; /* -q -a ... */
62
63 ipa_mem_type *m_anon; /* Anonymous memory allocations. */
64 ipa_mem_type *m_result; /* Memory used for query results. */
65
66 static char need_nl_raw = 0; /* Set if new line is needed
67 in raw output. */
68
69 /*
70 * If some rule has several buffers with statistics for
71 * several time intervals, then keep them in rule_stat_list
72 * structure.
73 */
74 struct rule_stat {
75 STAILQ_ENTRY(rule_stat) link; /* All rule_stat for rule. */
76 unsigned int n; /* Number of elements in buf. */
77 struct ipa_rule_stat *buf; /* Buffer with statistics for rule. */
78 const struct opt_tint *tint; /* Time interval. */
79 };
80
81 STAILQ_HEAD(rule_stat_list, rule_stat);
82
83 #ifdef WITH_LIMITS
84 /*
85 * If some limit has several buffers with statistics for
86 * several time intervals, then keep them in limit_stat_list
87 * structure.
88 */
89 struct limit_stat {
90 STAILQ_ENTRY(limit_stat) link; /* All limit_stat for limit. */
91 unsigned int n; /* Number of elements in buf. */
92 struct ipa_limit_state *buf; /* Buffer with statistics for limit. */
93 const struct opt_tint *tint; /* Time interval. */
94 };
95
96 STAILQ_HEAD(limit_stat_list, limit_stat);
97 #endif /* WITH_LIMITS */
98
99 #ifdef WITH_ANY_LIMITS
100 /*
101 * Description of several entities.
102 */
103 struct entity_desc {
104 unsigned int n; /* Number of elements in desc_list. */
105 struct ipa_entity_desc *desc_list; /* Array of descriptions. */
106 };
107 #endif
108
109 static int output(const char *, ...) ATTR_FORMAT(printf, 1, 2);
110
111 static int
output(const char * format,...)112 output(const char *format, ...)
113 {
114 va_list ap;
115
116 va_start(ap, format);
117 if (vprintf(format, ap) < 0) {
118 logmsg(IPA_LOG_ERR, "output: vprintf failed");
119 return (-1);
120 }
121 va_end(ap);
122 return (0);
123 }
124
125 static int
print_line(int len)126 print_line(int len)
127 {
128 while (len--)
129 if (printf("-") < 0) {
130 logmsg(IPA_LOG_ERR, "print_line: printf failed");
131 return (-1);
132 }
133 return (0);
134 }
135
136 static int
output_flush(void)137 output_flush(void)
138 {
139 if (fflush(stdout) != 0) {
140 logmsg(IPA_LOG_ERR, "output_flush: fflush(stdout)");
141 return (-1);
142 }
143 return (0);
144 }
145
146 static int
output_ipa_tm(const char * msg,char sep,const ipa_tm * tm,int is_set)147 output_ipa_tm(const char *msg, char sep, const ipa_tm *tm, int is_set)
148 {
149 if (output("%s %c ", msg, sep) < 0)
150 goto failed;
151 if (is_set) {
152 if (output("%d.%02d.%02d/%02d:%02d:%02d\n",
153 tm->tm_year, tm->tm_mon, tm->tm_mday,
154 tm->tm_hour, tm->tm_min, tm->tm_sec) < 0)
155 goto failed;
156 } else {
157 if (output("-\n") < 0)
158 goto failed;
159 }
160 return (0);
161
162 failed:
163 logbt("output_ipa_tm");
164 return (-1);
165 }
166
167 static int
cmp_entity_desc(const void * p1,const void * p2)168 cmp_entity_desc(const void *p1, const void *p2)
169 {
170 return (strcmp(
171 ((const struct ipa_entity_desc *)p1)->name,
172 ((const struct ipa_entity_desc *)p2)->name));
173 }
174
175 static int
output_desc_list_raw(const char * what,unsigned int n,const struct ipa_entity_desc * desc_list)176 output_desc_list_raw(const char *what, unsigned int n,
177 const struct ipa_entity_desc *desc_list)
178 {
179 size_t len, name_width, info_width;
180 const struct ipa_entity_desc *desc;
181 int nwidth, iwidth;
182
183 name_width = strlen(what);
184 info_width = sizeof("info") - 1;
185 for (desc = desc_list; desc < desc_list + n; ++desc) {
186 len = strlen(desc->name);
187 if (name_width < len)
188 name_width = len;
189 if (desc->info != NULL) {
190 len = strlen(desc->info);
191 if (info_width < len)
192 info_width = len;
193 }
194 }
195 ++info_width;
196
197 nwidth = (int)name_width;
198 iwidth = (int)info_width;
199
200 if (output("%-*s | Info\n", nwidth, what) < 0)
201 goto failed;
202
203 if (print_line(nwidth) < 0 || output("-+") < 0 ||
204 print_line(iwidth) < 0 || output("\n") < 0)
205 goto failed;
206
207 for (desc = desc_list; desc < desc_list + n; ++desc)
208 if ((desc->info != NULL ?
209 output("%-*s | %s\n", nwidth, desc->name, desc->info) :
210 output("%-*s |\n", nwidth, desc->name)) < 0)
211 goto failed;
212
213 if (print_line(nwidth) < 0 || output("-+") < 0 ||
214 print_line(iwidth) < 0 || output("\n\n") < 0)
215 goto failed;
216
217 if (output(" * %u line%s\n", n, plural_form(n)) < 0)
218 goto failed;
219
220 if (output_flush() < 0)
221 goto failed;
222
223 return (0);
224
225 failed:
226 logbt("output_entity_desc_raw");
227 return (-1);
228 }
229
230 static void
free_desc_list(unsigned int n,struct ipa_entity_desc * desc_list)231 free_desc_list(unsigned int n, struct ipa_entity_desc *desc_list)
232 {
233 if (desc_list != NULL) {
234 struct ipa_entity_desc *desc;
235
236 for (desc = desc_list; desc < desc_list + n; ++desc) {
237 mem_free(desc->name, m_result);
238 mem_free(desc->info, m_result);
239 }
240 mem_free(desc_list, m_result);
241 }
242 }
243
244 static int
show_rules_list(void)245 show_rules_list(void)
246 {
247 const struct st_list *st_list;
248 struct ipa_entity_desc *desc_list;
249 unsigned int n;
250 int rv;
251
252 st_list = cur_opt_st != NULL ? cur_opt_st->st_list : global_st_list;
253 rv = -1;
254
255 if (st_get_rules_list(st_list, &n, &desc_list) < 0) {
256 desc_list = NULL;
257 goto done;
258 }
259 qsort(desc_list, n, sizeof(*desc_list), cmp_entity_desc);
260 if (output_desc_list_raw("Rule", n, desc_list) < 0)
261 goto done;
262 rv = 0;
263 done:
264 free_desc_list(n, desc_list);
265 if (rv != 0)
266 logbt("show_rules_list");
267 return (rv);
268 }
269
270 static int
output_rule_stat_raw(const struct opt_rule * opt_rule)271 output_rule_stat_raw(const struct opt_rule *opt_rule)
272 {
273 uint64_t cnt_day, cnt_sum, cnt_tot;
274 const struct rule *rule;
275 const struct ipa_rule_stat *stat, *stat_end;
276 const struct rule_stat *rule_stat;
277 const struct rule_stat_list *rule_stat_list;
278 unsigned int curyear, curmon, curmday;
279 unsigned int ndays;
280
281 if (need_nl_raw) {
282 if (output("\n") < 0)
283 goto failed;
284 } else
285 need_nl_raw = 1;
286
287 rule = opt_rule->rule;
288 if (output("Rule : %s\nInfo : %s\n", rule->name,
289 rule->info != NULL ? rule->info : "") < 0)
290 goto failed;
291
292 rule_stat_list = opt_rule->data;
293 cnt_tot = 0;
294
295 STAILQ_FOREACH(rule_stat, rule_stat_list, link) {
296 if (output_ipa_tm("\nFrom", ':', &rule_stat->tint->tm1, 1) < 0)
297 goto failed;
298 if (output_ipa_tm("To ", ':', &rule_stat->tint->tm2, 1) < 0)
299 goto failed;
300 cnt_sum = 0;
301 if (rule_stat->n != 0) {
302 stat = rule_stat->buf;
303 stat_end = stat + rule_stat->n;
304 curyear = stat->year;
305 curmon = stat->mon;
306 curmday = stat->mday;
307 cnt_day = 0;
308 ndays = 1;
309 if (output("\nTimestamp |"
310 " Counter | Per day\n"
311 "-----------------------------+-----------"
312 "-----------+---------------------") < 0)
313 goto failed;
314 for (;;) {
315 if (output("\n%u.%02u.%02u/%02u:%02u:%02u-"
316 "%02u:%02u:%02u | %20"PRIu64" |",
317 stat->year, stat->mon, stat->mday,
318 stat->h1, stat->m1, stat->s1,
319 stat->h2, stat->m2, stat->s2,
320 stat->cnt) < 0)
321 goto failed;
322 if (cnt_day < UINT64_MAX - stat->cnt)
323 cnt_day += stat->cnt;
324 else
325 cnt_day = UINT64_MAX;
326 if (++stat == stat_end)
327 break;
328 if (curmday != stat->mday ||
329 curmon != stat->mon ||
330 curyear != stat->year) {
331 curmday = stat->mday;
332 curmon = stat->mon;
333 curyear = stat->year;
334 ndays++;
335 if (cnt_sum < UINT64_MAX - cnt_day)
336 cnt_sum += cnt_day;
337 else
338 cnt_sum = UINT64_MAX;
339 if (cnt_day != UINT64_MAX) {
340 if (output(" %20"PRIu64,
341 cnt_day) < 0)
342 goto failed;
343 } else {
344 if (output(" %20s",
345 "TOO_BIG") < 0)
346 goto failed;
347 }
348 cnt_day = 0;
349 }
350 }
351 if (cnt_day != UINT64_MAX) {
352 if (output(" %20"PRIu64, cnt_day) < 0)
353 goto failed;
354 } else {
355 if (output(" %20s", "TOO_BIG") < 0)
356 goto failed;
357 }
358 if (output("\n-----------------------------+"
359 "----------------------+----------------"
360 "-----") < 0)
361 goto failed;
362
363 if (cnt_sum < UINT64_MAX - cnt_day)
364 cnt_sum += cnt_day;
365 else
366 cnt_sum = UINT64_MAX;
367 } else
368 ndays = 0;
369 if (cnt_sum != UINT64_MAX) {
370 if (output("\n * Summary %"PRIu64" (%u day%s)\n",
371 cnt_sum, ndays, plural_form(ndays)) < 0)
372 goto failed;
373 } else {
374 if (output("\n * Summary TOO_BIG (%u day%s)\n",
375 ndays, plural_form(ndays)) < 0)
376 goto failed;
377 }
378 if (cnt_tot < UINT64_MAX - cnt_sum)
379 cnt_tot += cnt_sum;
380 else
381 cnt_tot = UINT64_MAX;
382 }
383
384 if (cnt_tot != UINT64_MAX) {
385 if (output("\n * Total %"PRIu64"\n", cnt_tot) < 0)
386 goto failed;
387 } else {
388 if (output("\n * Total TOO_BIG\n") < 0)
389 goto failed;
390 }
391
392 if (output_flush() < 0)
393 goto failed;
394
395 return (0);
396
397 failed:
398 logbt("output_rule_stat_raw");
399 return (-1);
400 }
401
402 static int
show_rules_stat(void)403 show_rules_stat(void)
404 {
405 const struct opt_tint *tint;
406 struct ipa_rule_stat *buf;
407 struct rule *rule;
408 struct opt_rule *opt_rule;
409 struct rule_stat *rule_stat, *rule_stat_next;
410 struct rule_stat_list *rule_stat_list;
411 unsigned int n;
412 int rv;
413
414 rv = -1;
415 STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
416 rule = opt_rule->rule;
417 if (rule->info == NULL)
418 if (st_get_rule_info(rule, &rule->info) < 0)
419 goto done;
420 rule_stat_list = mem_malloc(sizeof(*rule_stat_list), m_anon);
421 if (rule_stat_list == NULL)
422 goto done;
423 STAILQ_INIT(rule_stat_list);
424 opt_rule->data = rule_stat_list;
425
426 STAILQ_FOREACH(tint, &opt_tint_list, link) {
427 if (st_get_rule_stat(rule, &tint->tm1,
428 &tint->tm2, tint->exact, &n, &buf) < 0)
429 goto done;
430 rule_stat = mem_malloc(sizeof(*rule_stat), m_anon);
431 if (rule_stat == NULL) {
432 mem_free(buf, m_result);
433 goto done;
434 }
435 rule_stat->n = n;
436 rule_stat->buf = buf;
437 rule_stat->tint = tint;
438 STAILQ_INSERT_TAIL(rule_stat_list, rule_stat, link);
439 }
440 }
441 STAILQ_FOREACH(opt_rule, &opt_rules_list, link)
442 if (output_rule_stat_raw(opt_rule) < 0)
443 goto done;
444 rv = 0;
445 done:
446 STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
447 rule_stat_list = opt_rule->data;
448 if (rule_stat_list != NULL) {
449 STAILQ_FOREACH_SAFE(rule_stat, rule_stat_list, link,
450 rule_stat_next) {
451 mem_free(rule_stat->buf, m_result);
452 mem_free(rule_stat, m_anon);
453 }
454 mem_free(rule_stat_list, m_anon);
455 }
456 }
457 if (rv != 0)
458 logbt("show_rules_stat");
459 return (rv);
460 }
461
462 #ifdef WITH_ANY_LIMITS
463 static int
output_any_limits_list_raw(const struct opt_rule * opt_rule,const char * what)464 output_any_limits_list_raw(const struct opt_rule *opt_rule, const char *what)
465 {
466 const struct rule *rule;
467 const struct entity_desc *entity_desc;
468
469 if (need_nl_raw) {
470 if (output("\n") < 0)
471 goto failed;
472 } else
473 need_nl_raw = 1;
474
475 rule = opt_rule->rule;
476 if (output("Rule : %s\nInfo : %s\n\n", rule->name,
477 rule->info != NULL ? rule->info : "") < 0)
478 goto failed;
479
480 entity_desc = opt_rule->data;
481
482 if (output_desc_list_raw(what, entity_desc->n,
483 entity_desc->desc_list) < 0)
484 goto failed;
485
486 if (output_flush() < 0)
487 goto failed;
488
489 return (0);
490
491 failed:
492 logbt("output_any_limits_list_raw");
493 return (-1);
494 }
495 #endif /* WITH_ANY_LIMITS */
496
497 #ifdef WITH_LIMITS
498 static int
show_limits_list(void)499 show_limits_list(void)
500 {
501 struct rule *rule;
502 struct opt_rule *opt_rule;
503 struct entity_desc *entity_desc;
504 struct ipa_entity_desc *desc_list;
505 unsigned int n;
506 int rv;
507
508 rv = -1;
509 STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
510 rule = opt_rule->rule;
511 if (rule->info == NULL)
512 if (st_get_rule_info(rule, &rule->info) < 0)
513 goto done;
514 if (st_get_limits_list(rule, &n, &desc_list) < 0)
515 goto done;
516 entity_desc = mem_malloc(sizeof(*entity_desc), m_anon);
517 if (entity_desc == NULL) {
518 free_desc_list(n, desc_list);
519 goto done;
520 }
521 entity_desc->desc_list = desc_list;
522 entity_desc->n = n;
523 opt_rule->data = entity_desc;
524 qsort(desc_list, n, sizeof(*desc_list), cmp_entity_desc);
525 }
526 STAILQ_FOREACH(opt_rule, &opt_rules_list, link)
527 if (output_any_limits_list_raw(opt_rule, "Limit") < 0)
528 goto done;
529
530 rv = 0;
531 done:
532 STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
533 entity_desc = opt_rule->data;
534 if (entity_desc != NULL) {
535 free_desc_list(entity_desc->n, entity_desc->desc_list);
536 mem_free(entity_desc, m_anon);
537 }
538 }
539 if (rv != 0)
540 logbt("show_limits_list");
541 return (rv);
542 }
543
544 #define LIMIT_START_STR "Start "
545 #define LIMIT_RESTART_STR "Restart "
546 #define LIMIT_RESTART_EXEC_STR "Restart exec"
547 #define LIMIT_REACH_STR "Reach "
548 #define LIMIT_REACH_EXEC_STR "Reach exec "
549 #define LIMIT_EXPIRE_STR "Expire "
550 #define LIMIT_EXPIRE_EXEC_STR "Expire exec "
551 #define LIMIT_UPDATED_STR "Updated "
552
553 struct limit_event {
554 const char *name;
555 unsigned int set;
556 unsigned int idx;
557 };
558
559 #define EVENT_TBL_ENTRY(X) { \
560 LIMIT_ ## X ## _STR, IPA_LIMIT_EVENT_ ## X ## _SET, \
561 IPA_LIMIT_EVENT_ ## X \
562 }
563
564 static const struct limit_event limit_event_tbl[] = {
565 EVENT_TBL_ENTRY(START),
566 EVENT_TBL_ENTRY(RESTART),
567 EVENT_TBL_ENTRY(RESTART_EXEC),
568 EVENT_TBL_ENTRY(REACH),
569 EVENT_TBL_ENTRY(REACH_EXEC),
570 EVENT_TBL_ENTRY(EXPIRE),
571 EVENT_TBL_ENTRY(EXPIRE_EXEC),
572 EVENT_TBL_ENTRY(UPDATED)
573 };
574
575 #undef EVENT_TBL_ENTRY
576
577 static int
output_limit_stat_raw(const struct opt_limit * opt_limit)578 output_limit_stat_raw(const struct opt_limit *opt_limit)
579 {
580 const struct limit *limit;
581 const struct ipa_limit_state *state, *state_end;
582 const struct limit_stat *limit_stat;
583 const struct limit_stat_list *limit_stat_list;
584 const struct limit_event *event;
585
586 limit = opt_limit->limit;
587 if (output("\nLimit : %s\nInfo : %s\n",
588 limit->name, limit->info != NULL ? limit->info : "") < 0)
589 goto failed;
590
591 limit_stat_list = opt_limit->data;
592
593 STAILQ_FOREACH(limit_stat, limit_stat_list, link) {
594 if (limit_stat->tint == NULL) {
595 if (output("\nFrom : current\nTo : current\n") < 0)
596 goto failed;
597 } else {
598 if (output_ipa_tm("\nFrom ", ':',
599 &limit_stat->tint->tm1, 1) < 0)
600 goto failed;
601 if (output_ipa_tm("To ", ':',
602 &limit_stat->tint->tm2, 1) < 0)
603 goto failed;
604 }
605 state = limit_stat->buf;
606 state_end = state + limit_stat->n;
607 for (; state != state_end; ++state) {
608 if (output("\n-------------+"
609 "---------------------\n") < 0)
610 goto failed;
611 for (event = limit_event_tbl;
612 event < limit_event_tbl +
613 IPA_LIMIT_EVENT_NUM; ++event)
614 if (output_ipa_tm(event->name, '|',
615 &state->event_date[event->idx],
616 state->event_date_set & event->set) < 0)
617 goto failed;
618 if (output("Limit | %20"PRIu64
619 "\nCounter | %20"PRIu64"",
620 state->lim, state->cnt) < 0)
621 goto failed;
622 }
623 if (limit_stat->n != 0)
624 if (output("\n-------------+"
625 "---------------------\n") < 0)
626 goto failed;
627 if (output("\n * %u state%s\n", limit_stat->n,
628 plural_form(limit_stat->n)) < 0)
629 goto failed;
630 }
631
632 return (0);
633
634 failed:
635 logbt("output_limit_stat_raw");
636 return (-1);
637 }
638
639 static int
output_limits_stat_raw(const struct opt_rule * opt_rule)640 output_limits_stat_raw(const struct opt_rule *opt_rule)
641 {
642 const struct rule *rule;
643 const struct opt_limit *opt_limit;
644
645 if (need_nl_raw) {
646 if (output("\n") < 0)
647 goto failed;
648 } else
649 need_nl_raw = 1;
650
651 rule = opt_rule->rule;
652 if (output("Rule : %s\nInfo : %s\n",
653 rule->name, rule->info != NULL ? rule->info : "") < 0)
654 goto failed;
655
656 STAILQ_FOREACH(opt_limit, &opt_rule->opt_limits, link)
657 if (output_limit_stat_raw(opt_limit) < 0)
658 goto failed;
659
660 if (output_flush() < 0)
661 goto failed;
662
663 return (0);
664
665 failed:
666 logbt("output_limits_stat_raw");
667 return (-1);
668 }
669
670 static int
show_limits_stat(void)671 show_limits_stat(void)
672 {
673 const struct opt_tint *tint;
674 struct ipa_limit_state *buf;
675 struct rule *rule;
676 struct limit *limit;
677 struct opt_rule *opt_rule;
678 struct opt_limit *opt_limit;
679 struct limit_stat *limit_stat, *limit_stat_next;
680 struct limit_stat_list *limit_stat_list;
681 unsigned int n;
682 int rv;
683
684 rv = -1;
685 STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
686 rule = opt_rule->rule;
687 if (rule->info == NULL)
688 if (st_get_rule_info(rule, &rule->info) < 0)
689 goto done;
690 STAILQ_FOREACH(opt_limit, &opt_rule->opt_limits, link) {
691 limit = opt_limit->limit;
692 if (limit->info == NULL)
693 if (st_get_limit_info(rule, limit,
694 &limit->info) < 0)
695 goto done;
696 limit_stat_list = mem_malloc(sizeof(*limit_stat_list),
697 m_anon);
698 if (limit_stat_list == NULL)
699 goto done;
700 STAILQ_INIT(limit_stat_list);
701 opt_limit->data = limit_stat_list;
702
703 if (STAILQ_EMPTY(&opt_tint_list)) {
704 if (st_get_limit_stat(rule, limit,
705 (ipa_tm *)NULL, (ipa_tm *)NULL, &n,
706 &buf) < 0)
707 goto done;
708 limit_stat = mem_malloc(sizeof(*limit_stat),
709 m_anon);
710 if (limit_stat == NULL) {
711 mem_free(buf, m_result);
712 goto done;
713 }
714 limit_stat->n = n;
715 limit_stat->buf = buf;
716 limit_stat->tint = NULL;
717 STAILQ_INSERT_TAIL(limit_stat_list, limit_stat,
718 link);
719 } else STAILQ_FOREACH(tint, &opt_tint_list, link) {
720 if (st_get_limit_stat(rule, limit, &tint->tm1,
721 &tint->tm2, &n, &buf) < 0)
722 goto done;
723 limit_stat = mem_malloc(sizeof(*limit_stat),
724 m_anon);
725 if (limit_stat == NULL) {
726 mem_free(buf, m_result);
727 goto done;
728 }
729 limit_stat->n = n;
730 limit_stat->buf = buf;
731 limit_stat->tint = tint;
732 STAILQ_INSERT_TAIL(limit_stat_list, limit_stat,
733 link);
734 }
735 }
736 }
737
738 STAILQ_FOREACH(opt_rule, &opt_rules_list, link)
739 if (output_limits_stat_raw(opt_rule) < 0)
740 goto done;
741
742 rv = 0;
743 done:
744 STAILQ_FOREACH(opt_rule, &opt_rules_list, link)
745 STAILQ_FOREACH(opt_limit, &opt_rule->opt_limits, link) {
746 limit_stat_list = opt_limit->data;
747 if (limit_stat_list != NULL) {
748 STAILQ_FOREACH_SAFE(limit_stat, limit_stat_list,
749 link, limit_stat_next) {
750 mem_free(limit_stat->buf, m_result);
751 mem_free(limit_stat, m_anon);
752 }
753 mem_free(limit_stat_list, m_anon);
754 }
755 }
756
757 if (rv != 0)
758 logbt("show_limits_stat");
759 return (rv);
760 }
761
762
763 #endif /* WITH_LIMITS */
764
765 #ifdef WITH_THRESHOLDS
766 static int
show_thresholds_list(void)767 show_thresholds_list(void)
768 {
769 struct rule *rule;
770 struct entity_desc *entity_desc;
771 struct ipa_entity_desc *desc_list;
772 struct opt_rule *opt_rule;
773 unsigned int n;
774 int rv;
775
776 rv = -1;
777 STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
778 rule = opt_rule->rule;
779 if (rule->info == NULL)
780 if (st_get_rule_info(rule, &rule->info) < 0)
781 goto done;
782 if (st_get_thresholds_list(rule, &n, &desc_list) < 0)
783 goto done;
784 entity_desc = mem_malloc(sizeof(*entity_desc), m_anon);
785 if (entity_desc == NULL) {
786 free_desc_list(n, desc_list);
787 goto done;
788 }
789 entity_desc->desc_list = desc_list;
790 entity_desc->n = n;
791 opt_rule->data = entity_desc;
792 qsort(desc_list, n, sizeof(*desc_list), cmp_entity_desc);
793 }
794 STAILQ_FOREACH(opt_rule, &opt_rules_list, link)
795 if (output_any_limits_list_raw(opt_rule, "Threshold") < 0)
796 goto done;
797 rv = 0;
798 done:
799 STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
800 entity_desc = opt_rule->data;
801 if (entity_desc != NULL) {
802 free_desc_list(entity_desc->n, entity_desc->desc_list);
803 mem_free(entity_desc, m_anon);
804 }
805 }
806 if (rv != 0)
807 logbt("show_thresholds_list");
808 return (rv);
809 }
810
811 static int
output_threshold_stat_raw(const struct opt_threshold * opt_threshold)812 output_threshold_stat_raw(const struct opt_threshold *opt_threshold)
813 {
814 const struct threshold *threshold;
815 const struct ipa_threshold_state *state;
816
817 threshold = opt_threshold->threshold;
818 if (output("\nThreshold : %s\nInfo : %s\n\n",
819 threshold->name,
820 threshold->info != NULL ? threshold->info : "") < 0)
821 goto failed;
822
823 state = &opt_threshold->state;
824
825 if (opt_threshold->reged) {
826 if (output("----------+---------------------\n") < 0)
827 goto failed;
828 if (output_ipa_tm("Started ", '|', &state->tm_from, 1) < 0)
829 goto failed;
830 if (output_ipa_tm("Updated ", '|', &state->tm_updated, 1) < 0)
831 goto failed;
832 if (output("Threshold | %20"PRIu64"\nCounter | %20"PRIu64
833 "\n", state->thr, state->cnt) < 0)
834 goto failed;
835 if (output("----------+---------------------\n") < 0)
836 goto failed;
837 } else {
838 if (output(" * No state\n") < 0)
839 goto failed;
840 }
841
842 return (0);
843
844 failed:
845 logbt("output_threshold_stat_raw");
846 return (-1);
847 }
848
849 static int
output_thresholds_stat_raw(const struct opt_rule * opt_rule)850 output_thresholds_stat_raw(const struct opt_rule *opt_rule)
851 {
852 const struct rule *rule;
853 const struct opt_threshold *opt_threshold;
854
855 if (need_nl_raw) {
856 if (output("\n") < 0)
857 goto failed;
858 } else
859 need_nl_raw = 1;
860
861 rule = opt_rule->rule;
862 if (output("Rule : %s\nInfo : %s\n",
863 rule->name, rule->info != NULL ? rule->info : "") < 0)
864 goto failed;
865
866 STAILQ_FOREACH(opt_threshold, &opt_rule->opt_thresholds, link)
867 if (output_threshold_stat_raw(opt_threshold) < 0)
868 goto failed;
869
870 if (output_flush() < 0)
871 goto failed;
872
873 return (0);
874
875 failed:
876 logbt("output_thresholds_stat_raw");
877 return (-1);
878 }
879
880 static int
show_thresholds_stat(void)881 show_thresholds_stat(void)
882 {
883 struct rule *rule;
884 struct threshold *threshold;
885 struct opt_rule *opt_rule;
886 struct opt_threshold *opt_threshold;
887 int rv;
888
889 rv = -1;
890 STAILQ_FOREACH(opt_rule, &opt_rules_list, link) {
891 rule = opt_rule->rule;
892 if (rule->info == NULL)
893 if (st_get_rule_info(rule, &rule->info) < 0)
894 goto done;
895 STAILQ_FOREACH(opt_threshold, &opt_rule->opt_thresholds, link) {
896 threshold = opt_threshold->threshold;
897 if (threshold->info == NULL)
898 if (st_get_threshold_info(rule, threshold,
899 &threshold->info) < 0)
900 goto done;
901 if (st_get_threshold_stat(rule, threshold,
902 &opt_threshold->reged, &opt_threshold->state) < 0)
903 goto done;
904 }
905 }
906
907 STAILQ_FOREACH(opt_rule, &opt_rules_list, link)
908 if (output_thresholds_stat_raw(opt_rule) < 0)
909 goto done;
910
911 rv = 0;
912 done:
913 if (rv != 0)
914 logbt("show_thresholds_stat");
915 return (rv);
916 }
917 #endif /* WITH_THRESHOLDS */
918
919 int
ipastat_main(void)920 ipastat_main(void)
921 {
922 int rv;
923
924 /* Check whether there is any query in -q. */
925 if (a_flag != A_FLAG_RULES && STAILQ_EMPTY(&opt_rules_list)) {
926 logmsgx(IPA_LOG_WARNING, "ipastat_main: no query is given");
927 return (0);
928 }
929
930 if (pre_init_st_mods() < 0)
931 goto failed;
932
933 if (init_rules() < 0)
934 goto failed;
935
936 if (init_st_mods() < 0)
937 goto failed;
938
939 rv = 0;
940 switch (a_flag) {
941 case A_FLAG_ABSENT:
942 switch (cur_opt_rule->type) {
943 case OPT_RULE_RULE:
944 if (STAILQ_EMPTY(&opt_tint_list))
945 opt_tint_init();
946 rv = show_rules_stat();
947 break;
948 #ifdef WITH_LIMITS
949 case OPT_RULE_LIMIT:
950 rv = show_limits_stat();
951 break;
952 #endif
953 #ifdef WITH_THRESHOLDS
954 case OPT_RULE_THRESHOLD:
955 rv= show_thresholds_stat();
956 break;
957 #endif
958 }
959 break;
960 case A_FLAG_RULES:
961 rv = show_rules_list();
962 break;
963 #ifdef WITH_LIMITS
964 case A_FLAG_LIMITS:
965 rv = show_limits_list();
966 break;
967 #endif
968 #ifdef WITH_THRESHOLDS
969 case A_FLAG_THRESHOLDS:
970 rv = show_thresholds_list();
971 break;
972 #endif
973 }
974
975 if (rv != 0)
976 goto failed;
977 return (0);
978
979 failed:
980 logbt("ipastat_main");
981 return (-1);
982 }
983
984 int
deinit_all(void)985 deinit_all(void)
986 {
987 int rv;
988
989 rv = 0;
990 if (deinit_rules() < 0)
991 rv = -1;
992 if (deinit_st_mods() < 0)
993 rv = -1;
994 if (rv != 0)
995 logbt("deinit_all");
996 return (rv);
997 }
998
999 /*
1000 * Free all resources allocated during work and validate internal
1001 * structures after releasing memory.
1002 */
1003 int
free_all(void)1004 free_all(void)
1005 {
1006 unsigned int n;
1007 int rv;
1008
1009 free_rules();
1010 if (!STAILQ_EMPTY(&rules_list)) {
1011 logmsgx(IPA_LOG_ERR, "internal error: free_all: "
1012 "rules_list is not empty");
1013 return (-1);
1014 }
1015 if (!STAILQ_EMPTY_HEAD_VALID(&rules_list)) {
1016 logmsgx(IPA_LOG_ERR, "internal error: free_all: "
1017 "empty rules_list list is in inconsistent state");
1018 return (-1);
1019 }
1020
1021 n = mzone_nused(rule_mzone);
1022 if (n != 0) {
1023 logmsgx(IPA_LOG_ERR, "internal error: free_all: "
1024 "rule_mzone is not empty: %u", n);
1025 return (-1);
1026 }
1027 mzone_deinit(rule_mzone);
1028
1029 #ifdef WITH_LIMITS
1030 n = mzone_nused(limit_mzone);
1031 if (n != 0) {
1032 logmsgx(IPA_LOG_ERR, "internal error: free_all: "
1033 "limit_mzone is not empty: %u", n);
1034 return (-1);
1035 }
1036 mzone_deinit(limit_mzone);
1037 #endif
1038 #ifdef WITH_THRESHOLDS
1039 n = mzone_nused(threshold_mzone);
1040 if (n != 0) {
1041 logmsgx(IPA_LOG_ERR, "internal error: free_all: "
1042 "threshold_mzone is not empty: %u", n);
1043 return (-1);
1044 }
1045 mzone_deinit(threshold_mzone);
1046 #endif
1047
1048 free_rulepats();
1049
1050 free_st_lists();
1051
1052 memfunc_deinit_1(0);
1053
1054 rv = unload_all_mods();
1055 if (rv < 0)
1056 logmsgx(IPA_LOG_ERR, "free_all: cannot correctly unload "
1057 "all modules");
1058
1059 memfunc_deinit_2(0);
1060 return (rv);
1061 }
1062