1 /*-
2 * Copyright (c) 2003-2004 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: ipa_autorules.c,v 1.3.2.1 2011/11/15 18:12:29 simon Exp $";
32 #endif /* !lint */
33
34 #include <sys/types.h>
35
36 #include <regex.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "ipa_mod.h"
42
43 #include "queue.h"
44
45 #include "dlapi.h"
46 #include "confcommon.h"
47 #include "memfunc.h"
48 #include "parser.h"
49
50 #include "ipa_ac.h"
51 #include "ipa_db.h"
52 #include "ipa_time.h"
53
54 #include "ipa_ctl.h"
55 #include "ipa_cmd.h"
56 #include "ipa_conf.h"
57 #include "ipa_log.h"
58 #include "ipa_main.h"
59 #include "ipa_rules.h"
60 #include "ipa_autorules.h"
61
62 unsigned int nautorules; /* Number of autorules. */
63 unsigned int ndynrules; /* Number of dynamic rules. */
64
65 #ifdef WITH_AUTORULES
66
67 signed char debug_autorule; /* debug_autorule parameter. */
68
69 struct autorule *autorules; /* Array of autorules. */
70 ipa_marray *autorules_marray; /* Marray of autorules. */
71
72 struct autorules_list autorules_list; /* List of all autorules. */
73
74 #define AUTORULE(x) &autorules[(x)] /* Pointer to autorule by number. */
75
76 static struct rule **rules_ptr; /* Array of pointers to rules. */
77 ipa_marray *rules_ptr_marray; /* Marray for array of ptrs to rules. */
78
79 #define RULE(x) rules_ptr[(x)] /* Pointer to rule by number. */
80
81 /* Time when to check active autorules. */
82 unsigned int autorules_active_check_sec;
83
84 /* Time when to check inactive autorules. */
85 unsigned int autorules_inactive_check_sec;
86
87 /* Active/inactive autorules queue. */
88 TAILQ_HEAD(autorules_queue, autorule);
89 static struct autorules_queue autorules_active;
90 static struct autorules_queue autorules_inactive;
91
92 /*
93 * Return pointer to autorule with the given name.
94 */
95 struct autorule *
autorule_by_name(const char * name)96 autorule_by_name(const char *name)
97 {
98 struct autorule *autorule;
99 unsigned int i;
100
101 for (i = 0, autorule = autorules; i < nautorules; ++autorule, ++i)
102 if (strcmp(name, autorule->name) == 0)
103 return (autorule);
104 return (NULL);
105 }
106
107 /*
108 * Set autorule active or inactive in modules that it uses.
109 */
110 static int
mod_set_autorule_active(struct autorule * autorule,int active)111 mod_set_autorule_active(struct autorule *autorule, int active)
112 {
113 if ((autorule->arule_flags & AUTORULE_FLAG_ACTIVE) ==
114 (active ? AUTORULE_FLAG_ACTIVE : 0)) {
115 logmsgx(IPA_LOG_ERR, "internal error: mod_set_autorule_active"
116 "(%s, %d): autorule is already %s", autorule->name,
117 active, active_msg[active]);
118 return (-1);
119 }
120
121 if (debug_worktime)
122 logdbg("autorule %s: set autorule %s",
123 autorule->name, active_msg[active]);
124
125 if (active)
126 AUTORULE_SET_ACTIVE(autorule);
127 else
128 AUTORULE_SET_INACTIVE(autorule);
129
130 if (ac_set_autorule_active(autorule, active) < 0) {
131 logbt("mod_set_autorule_active");
132 return (-1);
133 }
134
135 return (0);
136 }
137
138 /*
139 * Log information about inactive autorules.
140 */
141 static void
show_inactive_autorules(void)142 show_inactive_autorules(void)
143 {
144 const struct autorule *autorule;
145
146 logdbg("inactive autorules list:");
147 TAILQ_FOREACH(autorule, &autorules_inactive, queue)
148 logdbg(" active_sec %s, autorule %s",
149 sec_str(autorule->worktime->active_sec), autorule->name);
150 }
151
152 /*
153 * Move am autorule from the active autorules queue to the inactive
154 * autorules queue.
155 */
156 static int
set_autorule_inactive(struct autorule * autorule1)157 set_autorule_inactive(struct autorule *autorule1)
158 {
159 struct autorule *autorule2;
160
161 /* Inform modules that autorule becomes inactive. */
162 if (mod_set_autorule_active(autorule1, 0) < 0) {
163 logbt("set_autorule_inactive");
164 return (-1);
165 }
166
167 /* Remove the autorule from the active autorules queue. */
168 TAILQ_REMOVE(&autorules_active, autorule1, queue);
169
170 /*
171 * Add the autorule to the inactive autorules queue,
172 * keep that queue sorted.
173 */
174 TAILQ_FOREACH(autorule2, &autorules_inactive, queue)
175 if (autorule1->worktime->active_sec <
176 autorule2->worktime->active_sec) {
177 TAILQ_INSERT_BEFORE(autorule2, autorule1, queue);
178 goto done;
179 }
180 TAILQ_INSERT_TAIL(&autorules_inactive, autorule1, queue);
181 done:
182 if (debug_worktime)
183 show_inactive_autorules();
184
185 autorules_inactive_check_sec =
186 TAILQ_FIRST(&autorules_inactive)->worktime->active_sec;
187
188 return (0);
189 }
190
191 /*
192 * Move an autorule from the inactive autorules queue to the
193 * active autorules queue.
194 */
195 static int
set_autorule_active(struct autorule * autorule)196 set_autorule_active(struct autorule *autorule)
197 {
198 /* Inform modules that autorule becomes active. */
199 if (mod_set_autorule_active(autorule, 1) < 0) {
200 logbt("set_autorule_active");
201 return (-1);
202 }
203
204 /* Remove the autorule from the inactive autorules queue. */
205 TAILQ_REMOVE(&autorules_inactive, autorule, queue);
206
207 /* Add the rule to the active autorules queue. */
208 TAILQ_INSERT_TAIL(&autorules_active, autorule, queue);
209
210 /* Get new value of autorules_inactive_check_sec. */
211 autorules_inactive_check_sec = TAILQ_EMPTY(&autorules_inactive) ?
212 EVENT_NOT_SCHEDULED :
213 TAILQ_FIRST(&autorules_inactive)->worktime->active_sec;
214
215 /* Check if rules_active_check_sec should be modified. */
216 if (autorules_active_check_sec > autorule->update_tevent->event_sec)
217 autorules_active_check_sec = autorule->update_tevent->event_sec;
218 if (autorules_active_check_sec > autorule->worktime->inactive_sec)
219 autorules_active_check_sec = autorule->worktime->inactive_sec;
220
221 return (0);
222 }
223
224 /*
225 * Sort inactive autorules.
226 */
227 static void
sort_inactive_autorules(void)228 sort_inactive_autorules(void)
229 {
230 struct autorule *a1, *a1_next, *a2;
231
232 if (TAILQ_EMPTY(&autorules_inactive))
233 autorules_inactive_check_sec = EVENT_NOT_SCHEDULED;
234 else {
235 a1 = TAILQ_FIRST(&autorules_inactive);
236 TAILQ_INIT(&autorules_inactive);
237 for (; a1 != NULL; a1 = a1_next) {
238 a1_next = TAILQ_NEXT(a1, queue);
239 if (a1->worktime->active_sec != EVENT_NOT_SCHEDULED) {
240 /* Will be active in current day. */
241 TAILQ_FOREACH(a2, &autorules_inactive, queue)
242 if (a1->worktime->active_sec <=
243 a2->worktime->active_sec) {
244 TAILQ_INSERT_BEFORE(a2, a1,
245 queue);
246 goto next;
247 }
248 }
249 TAILQ_INSERT_TAIL(&autorules_inactive, a1, queue);
250 next: ;
251 }
252 autorules_inactive_check_sec =
253 TAILQ_FIRST(&autorules_inactive)->worktime->active_sec;
254 }
255
256 if (debug_worktime)
257 show_inactive_autorules();
258 }
259
260 /*
261 * Make initialization for all autorules.
262 */
263 int
init_autorules(void)264 init_autorules(void)
265 {
266 struct autorule *autorule;
267 struct rule *rule;
268
269 /* Initialize autorules queues. */
270 TAILQ_INIT(&autorules_inactive);
271 TAILQ_INIT(&autorules_active);
272
273 /* Flush number of dynamic rules. */
274 ndynrules = 0;
275
276 if (nautorules == 0)
277 return (0);
278
279 /* Initialize each autorule in accounting modules. */
280 STAILQ_FOREACH(autorule, &autorules_list, link) {
281 if (ac_init_autorule(autorule) < 0) {
282 logbt("init_autorules");
283 return (-1);
284 }
285 TAILQ_INSERT_TAIL(&autorules_active, autorule, queue);
286 }
287
288 /* Create rules_ptr_marray. */
289 rules_ptr_marray = marray_init(MARRAY_NAME(rules_ptr),
290 "Pointers to rules", 0, (void *)&rules_ptr, sizeof(struct rule *),
291 nstatrules + 1, RULE_NALLOC);
292 if (rules_ptr_marray == NULL) {
293 logmsgx(IPA_LOG_ERR, "init_autorules: marray_init failed");
294 return (-1);
295 }
296
297 /* Mark entries in rules_ptr for static rules as used. */
298 TAILQ_FOREACH(rule, &rules_list, list)
299 if (marray_alloc(rules_ptr_marray, &rule->no, 1) < 0) {
300 logmsgx(IPA_LOG_ERR, "init_autorules: "
301 "marray_alloc failed");
302 return (-1);
303 }
304
305 return (0);
306 }
307
308 /*
309 * Deinitialize one autorule.
310 */
311 static int
deinit_autorule(struct autorule * autorule)312 deinit_autorule(struct autorule *autorule)
313 {
314 int rv;
315
316 /* Deinitialize in modules. */
317 rv = 0;
318 if (ac_deinit_autorule(autorule) < 0) {
319 logbt("deinit_autorule");
320 rv = -1;
321 }
322
323 /* Decrease ref_count for accounting systems. */
324 if (AUTORULE_IS_ACTIVE(autorule))
325 if (ac_dec_ref_count(autorule->ac_list) < 0) {
326 logmsgx(IPA_LOG_ERR, "autorule %s: deinit_autorule: "
327 "ac_dec_ref_count failed", autorule->name);
328 rv = -1;
329 }
330
331 /* And free all memory used by a autorule. */
332 mem_free(autorule->name, m_anon);
333 cmds_rule_free(&autorule->rc[RC_STARTUP]);
334 cmds_rule_free(&autorule->rc[RC_SHUTDOWN]);
335 #ifdef WITH_LIMITS
336 free_limits(RULE_FLAG_FREE_LIMITS, &autorule->limits, 0);
337 #endif
338 #ifdef WITH_THRESHOLDS
339 free_thresholds(RULE_FLAG_FREE_THRESHOLDS, &autorule->thresholds, 0);
340 #endif
341
342 return (rv);
343 }
344
345 /*
346 * Make deinitialization for all autorules.
347 */
348 int
deinit_autorules(void)349 deinit_autorules(void)
350 {
351 struct autorule *autorule;
352 int rv;
353
354 if (nautorules == 0)
355 return (0);
356
357 rv = 0;
358 STAILQ_FOREACH(autorule, &autorules_list, link)
359 if (deinit_autorule(autorule) < 0) {
360 logbt("deinit_autorules");
361 rv = -1;
362 }
363
364 marray_deinit(autorules_marray);
365
366 if (ndynrules != 0) {
367 logmsgx(IPA_LOG_ERR, "internal error: deinit_autorules: "
368 "ndynrules is not zero: %u", ndynrules);
369 rv = -1;
370 }
371
372 if (rules_ptr_marray != NULL) {
373 unsigned int n;
374
375 n = marray_nused(rules_ptr_marray);
376 if (n != 0) {
377 logmsgx(IPA_LOG_ERR, "internal error: "
378 "deinit_autorules: rules_ptr_marray is "
379 "not empty: %u", n);
380 rv = -1;
381 }
382 marray_deinit(rules_ptr_marray);
383 }
384
385 return (rv);
386 }
387
388 /*
389 * Inherit settings for dynamic rule from its autorule, then inherit
390 * everythinh as for static rules.
391 */
392 static int
dyn_rule_inherit(const struct autorule * autorule,struct rule * rule)393 dyn_rule_inherit(const struct autorule *autorule, struct rule *rule)
394 {
395 unsigned int x;
396
397 /* Dynamic rule inherits non-NULL update_tevent from its autorule. */
398 rule->update_tevent = autorule->update_tevent;
399
400 rule->append_tevent = autorule->append_tevent;
401 rule->worktime = autorule->worktime_rule;
402
403 /* Dynamic rule inherits non-NULL ac_list from autorule. */
404 rule->ac_list = autorule->ac_list;
405 ac_inc_ref_count(rule->ac_list);
406
407 rule->db_list = autorule->db_list;
408
409 #ifdef WITH_RULES
410 /* Dynamic rules cannot have ac_gather_* parameters. */
411 rule->acg_add_pat = rule->acg_sub_pat = NULL;
412 SLIST_INIT(&rule->acgs);
413 #endif
414
415 rule->debug_exec = autorule->debug_exec;
416 rule_init_cmds(rule);
417 #ifdef WITH_LIMITS
418 rule->debug_limit = autorule->debug_limit;
419 rule->debug_limit_init = autorule->debug_limit_init;
420 #endif
421 #ifdef WITH_THRESHOLDS
422 rule->debug_threshold = autorule->debug_threshold;
423 rule->debug_threshold_init = autorule->debug_threshold_init;
424 #endif
425
426 #ifdef CTL_CHECK_CREDS
427 rule->ctl_rule_acl = autorule->ctl_rule_acl;
428 #endif
429
430 /*
431 * At this point everything is ready in a rule for possible
432 * deinit_dyn_rule() invocation.
433 */
434
435 for (x = 0; x < 2; ++x) {
436 if (!autorule->rc[x].cmds.sect_set)
437 continue;
438 if (cmds_rule_copy(rule, &rule->rc[x], &autorule->rc[x]) < 0) {
439 logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: "
440 "cannot copy all commands from autorule %s "
441 "{ %s {}}", rule->name, autorule->name,
442 rc_sect_name[x]);
443 return (-1);
444 }
445 }
446
447 #ifdef WITH_LIMITS
448 if (!STAILQ_EMPTY(&autorule->limits))
449 if (copy_limits(rule, &autorule->limits) < 0) {
450 logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: "
451 "cannot copy all limits from autorule %s",
452 rule->name, autorule->name);
453 return (-1);
454 }
455 #endif
456 #ifdef WITH_THRESHOLDS
457 if (!STAILQ_EMPTY(&autorule->thresholds))
458 if (copy_thresholds(rule, &autorule->thresholds) < 0) {
459 logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: "
460 "cannot copy all thresholds from autorule %s",
461 rule->name, autorule->name);
462 return (-1);
463 }
464 #endif
465
466 /* Inherit settings as for static rules. */
467 if (rule_inherit(rule) < 0) {
468 logbt("dyn_rule_inherit");
469 return (-1);
470 }
471
472 return (0);
473 }
474
475 /*
476 * Deinitialize one dynamic rule.
477 */
478 int
deinit_dyn_rule(struct rule * rule)479 deinit_dyn_rule(struct rule *rule)
480 {
481 marray_free(rules_ptr_marray, rule->no);
482 --ndynrules;
483 if (deinit_rule(rule) < 0) {
484 logbt("deinit_dyn_rule");
485 return (-1);
486 }
487 return (0);
488 }
489
490 /*
491 * Initialize one dynamic rule.
492 */
493 static int
init_dyn_rule(const struct autorule * autorule,struct rule * rule)494 init_dyn_rule(const struct autorule *autorule, struct rule *rule)
495 {
496 rule->newstat = 0;
497 if (rule->append_tevent == NULL)
498 rule->append_sec = EVENT_NOT_SCHEDULED;
499 if (ac_init_dynrule(autorule, rule) < 0)
500 goto failed;
501 if (db_init_dynrule(autorule, rule) < 0)
502 goto failed;
503 return (0);
504
505 failed:
506 logbt("init_dyn_rule");
507 return (-1);
508 }
509
510 /*
511 * Create a dynamic rule from the autorule, this function is invoked
512 * from the ipa_ac_mod's ac_get_stat() function.
513 */
514 int
create_rule(const char * mod_name,unsigned int autoruleno,const char * rule_name,const char * rule_info)515 create_rule(const char *mod_name, unsigned int autoruleno,
516 const char *rule_name, const char *rule_info)
517 {
518 struct rule *rule;
519 struct autorule *autorule;
520 #ifdef WITH_LIMITS
521 struct limit *limit;
522 #endif
523 #ifdef WITH_THRESHOLDS
524 struct threshold *threshold;
525 #endif
526 unsigned int ruleno;
527
528 /* Validate autorule number. */
529 if (autoruleno >= nautorules) {
530 logmsgx(IPA_LOG_ERR, "create_rule: module %s tries to create "
531 "dynamic rule from autorule with number %u and such "
532 "autorule does not exist", mod_name, autoruleno);
533 return (-1);
534 }
535 autorule = AUTORULE(autoruleno);
536
537 /* Check if there is already rule with the given name. */
538 if (validate_name(rule_name) < 0) {
539 logmsgx(IPA_LOG_ERR, "autorule %s: create_rule: module %s "
540 "specified illegal rule name \"%s\"", autorule->name,
541 mod_name, rule_name);
542 return (-1);
543 }
544 rule = rule_by_name(rule_name);
545 if (rule != NULL) {
546 logmsgx(IPA_LOG_WARNING, "autorule %s: create_rule: module %s "
547 "is trying to create duplicated rule %s",
548 autorule->name, mod_name, rule_name);
549 return (-2);
550 }
551
552 /* Find first unused rule number. */
553 if (marray_alloc(rules_ptr_marray, &ruleno, 0) < 0) {
554 logmsgx(IPA_LOG_ERR, "rule %s: create_rule: "
555 "marray_alloc failed", rule_name);
556 return (-1);
557 }
558
559 /* Allocate memory for a rule. */
560 rule = mzone_alloc(rule_mzone);
561 if (rule == NULL) {
562 logmsgx(IPA_LOG_ERR, "rule %s: create_rule: "
563 "mzone_alloc failed", rule_name);
564 marray_free(rules_ptr_marray, ruleno);
565 return (-1);
566 }
567
568 rule->name = mem_strdup(rule_name, m_anon);
569 if (rule->name == NULL) {
570 logmsgx(IPA_LOG_ERR, "rule %s: create_rule: "
571 "mem_strdup for rule name failed", rule_name);
572 mzone_free(rule_mzone, rule);
573 marray_free(rules_ptr_marray, ruleno);
574 return (-1);
575 }
576
577 RULE(ruleno) = rule;
578 rules_hash_add(rule);
579 TAILQ_INSERT_TAIL(&rules_list, rule, list);
580
581 rule->no = ruleno;
582 rule->cnt_neg = 0;
583 ++ndynrules;
584 #ifdef WITH_RULES
585 rule->acg_add_pat = rule->acg_sub_pat = NULL;
586 SLIST_INIT(&rule->acgs);
587 #endif
588 #ifdef WITH_LIMITS
589 STAILQ_INIT(&rule->limits);
590 #endif
591 #ifdef WITH_THRESHOLDS
592 STAILQ_INIT(&rule->thresholds);
593 #endif
594 rule->info = NULL;
595
596 rule->rule_flags = RULE_FLAG_ACTIVE | RULE_FLAG_QUEUED |
597 RULE_FLAG_DYNAMIC;
598 queue_active_rule(rule);
599
600 if (dyn_rule_inherit(autorule, rule) < 0) {
601 logmsgx(IPA_LOG_ERR, "rule %s: create_rule: cannot inherit "
602 "all settings for dynamic rule", rule_name);
603 goto failed;
604 }
605
606 #ifdef WITH_RULES
607 if (has_ac_gather)
608 if (init_acg(rule) < 0)
609 goto failed;
610 #endif
611
612 if (rule_info != NULL) {
613 rule->info = mem_strdup(rule_info, m_anon);
614 if (rule->info == NULL) {
615 logmsgx(IPA_LOG_ERR, "rule %s: create_rule: "
616 "mem_strdup for rule_info failed", rule_name);
617 goto failed;
618 }
619 }
620
621 if (init_dyn_rule(autorule, rule) < 0)
622 goto failed;
623
624 #ifdef WITH_LIMITS
625 if (init_limits(rule) < 0)
626 goto failed;
627 #endif
628 #ifdef WITH_THRESHOLDS
629 if (init_thresholds(rule) < 0)
630 goto failed;
631 #endif
632
633 if (run_cmds_rule(rule, RC_STARTUP) < 0)
634 goto failed;
635
636 /*
637 * By default any new rule is active as its limits and thresholds are.
638 * First ac_get_rule_stat() for a new dynamic rule returns statistics.
639 */
640
641 #ifdef WITH_LIMITS
642 STAILQ_FOREACH(limit, &rule->limits, link)
643 if (WT_IS_INACTIVE(limit->worktime))
644 if (set_limit_inactive(rule, limit) < 0)
645 goto failed;
646 #endif
647
648 #ifdef WITH_THRESHOLDS
649 STAILQ_FOREACH(threshold, &rule->thresholds, link)
650 if (WT_IS_INACTIVE(threshold->worktime))
651 if (set_threshold_inactive(rule, threshold) < 0)
652 goto failed;
653 #endif
654
655 if (WT_IS_INACTIVE(rule->worktime)) {
656 if (set_rule_inactive(rule) < 0)
657 goto failed;
658 } else {
659 /* If a rule is active, then check it immediately. */
660 rule->check_sec = 0;
661 if (db_append_rule(rule, &uint64_zero, 1) < 0)
662 goto failed;
663 }
664
665 autorule->nrules++;
666 rule->autoruleno = autoruleno;
667
668 if (debug_autorule)
669 logdbg("create_rule: module %s created dynamic rule %s "
670 "number %u from autorule %s", mod_name, rule_name,
671 ruleno, autorule->name);
672 return (0);
673
674 failed:
675 (void)deinit_dyn_rule(rule);
676 free_rule(rule);
677 logbt("create_rule");
678 return (-1);
679 }
680
681 /*
682 * Delete a dynamic rule previously created from an autorule,
683 * this function is invoked from the ipa_ac_mod.
684 */
685 int
delete_rule(const char * mod_name,unsigned int ruleno)686 delete_rule(const char *mod_name, unsigned int ruleno)
687 {
688 struct autorule *autorule;
689 struct rule *rule;
690 int rv;
691
692 /* Validate rule number. */
693 if (ruleno < nstatrules) {
694 logmsgx(IPA_LOG_ERR, "delete_rule: module %s is trying to "
695 "delete rule with number %u and this rule is not dynamic",
696 mod_name, ruleno);
697 return (-1);
698 }
699 if (!marray_check_index(rules_ptr_marray, ruleno)) {
700 logmsgx(IPA_LOG_ERR, "delete_rule: module %s is trying to "
701 "delete rule with number %u and this rule does not exist",
702 mod_name, ruleno);
703 return (-1);
704 }
705
706 /* Rule exists and is dynamic, delete it. */
707 rule = RULE(ruleno);
708 rv = 0;
709 if (run_cmds_rule(rule, RC_SHUTDOWN) < 0)
710 rv = -1;
711 if (deinit_dyn_rule(rule) < 0)
712 rv = -1;
713 if (rv < 0)
714 logbt("delete_rule");
715
716 autorule = AUTORULE(rule->autoruleno);
717 autorule->nrules--;
718
719 if (debug_autorule)
720 logdbg("delete_rule: module %s deleted rule %s number %u, "
721 "created from autorule %s", mod_name, rule->name,
722 ruleno, autorule->name);
723
724 free_rule(rule);
725 return (rv);
726 }
727
728 /*
729 * This function is called from newday().
730 */
731 int
autorules_newday(void)732 autorules_newday(void)
733 {
734 struct autorule *autorule;
735
736 autorules_active_check_sec = EVENT_NOT_SCHEDULED;
737
738 STAILQ_FOREACH(autorule, &autorules_list, link) {
739 if (WT_IS_INACTIVE(autorule->worktime)) {
740 if (AUTORULE_IS_ACTIVE(autorule))
741 if (set_autorule_inactive(autorule) < 0)
742 goto failed;
743 } else {
744 if (AUTORULE_IS_INACTIVE(autorule))
745 if (set_autorule_active(autorule) < 0)
746 goto failed;
747 if (autorules_active_check_sec >
748 autorule->update_tevent->event_sec)
749 autorules_active_check_sec =
750 autorule->update_tevent->event_sec;
751 if (autorules_active_check_sec >
752 autorule->worktime->inactive_sec)
753 autorules_active_check_sec =
754 autorule->worktime->inactive_sec;
755 }
756 }
757
758 sort_inactive_autorules();
759 return (0);
760
761 failed:
762 logbt("autorules_newday");
763 return (-1);
764 }
765
766 /*
767 * Check whether it is time to make some autorule active.
768 * This function is called when autorules_inactive_check_sec <= cursec.
769 */
770 int
check_inactive_autorules(void)771 check_inactive_autorules(void)
772 {
773 struct autorule *autorule, *autorule_next;
774
775 for (autorule = TAILQ_FIRST(&autorules_inactive); autorule != NULL;
776 autorule = autorule_next) {
777 if (autorule->worktime->inactive_sec <= cursec) {
778 /* It's time to make autorule active. */
779 autorule_next = TAILQ_NEXT(autorule, queue);
780 if (set_autorule_active(autorule) < 0) {
781 logbt("check_inactive_autorules");
782 return (-1);
783 }
784 } else {
785 /* Set next time of this function invocation. */
786 autorules_inactive_check_sec =
787 autorule->worktime->active_sec;
788 return (0);
789 }
790 }
791
792 /* No more inactive autorules. */
793 autorules_inactive_check_sec = EVENT_NOT_SCHEDULED;
794 return (0);
795 }
796
797 /*
798 * Check whether it is time to make some autorule inactive.
799 * This function is called when autorules_active_check_sec <= cursec.
800 */
801 int
check_active_autorules(void)802 check_active_autorules(void)
803 {
804 struct autorule *autorule;
805
806 autorules_active_check_sec = EVENT_NOT_SCHEDULED;
807
808 TAILQ_FOREACH(autorule, &autorules_active, queue) {
809 if (WT_IS_INACTIVE(autorule->worktime)) {
810 /* Autorule became inactive. */
811 if (!newday_flag)
812 if (set_autorule_inactive(autorule) < 0) {
813 logbt("check_active_autorules");
814 return (-1);
815 }
816 } else {
817 /* Autorule is still active. */
818 if (autorules_active_check_sec >
819 autorule->worktime->inactive_sec)
820 autorules_active_check_sec =
821 autorule->worktime->inactive_sec;
822 if (autorules_active_check_sec >
823 autorule->update_tevent->event_sec)
824 autorules_active_check_sec =
825 autorule->update_tevent->event_sec;
826 }
827 }
828
829 return (0);
830 }
831
832 /*
833 * Finish checks with autorules and inherit settings from global{}
834 * in all autorule{} sections.
835 */
836 int
autorules_inherit(void)837 autorules_inherit(void)
838 {
839 #ifdef WITH_LIMITS
840 struct limit *limit;
841 #endif
842 #ifdef WITH_THRESHOLDS
843 struct threshold *threshold;
844 #endif
845 const struct ac_list *ac_list;
846 struct autorule *autorule;
847 unsigned int i;
848
849 marray_minimize(autorules_marray);
850 for (i = 0, autorule = autorules; i < nautorules; ++autorule, ++i) {
851 STAILQ_INSERT_TAIL(&autorules_list, autorule, link);
852 ac_list = autorule->ac_list != NULL ?
853 autorule->ac_list : global_ac_list;
854 if (ac_list != NULL && !STAILQ_EMPTY(ac_list))
855 if (STAILQ_NEXT(STAILQ_FIRST(ac_list), link) != NULL) {
856 logconfe("autorule %s: only one accounting "
857 "system can be used", autorule->name);
858 return (-1);
859 }
860 if (mimic_real_config) {
861 if (autorule->ac_list == NULL) {
862 autorule->ac_list = global_ac_list;
863 ac_inc_ref_count(global_ac_list);
864 }
865 if (autorule->update_tevent == NULL)
866 autorule->update_tevent = global_update_tevent;
867 if (autorule->worktime == NULL)
868 autorule->worktime = global_worktime;
869 cmds_rule_set_sync(&autorule->rc[RC_STARTUP]);
870 cmds_rule_set_sync(&autorule->rc[RC_SHUTDOWN]);
871 }
872 # ifdef WITH_LIMITS
873 STAILQ_FOREACH(limit, &autorule->limits, link) {
874 if (check_worktime_subset(autorule->worktime_rule,
875 limit->worktime) < 0) {
876 logconfe("autorule %s, limit %s: limit's "
877 "\"worktime\" must be a subset of "
878 "autorule's \"worktime_rule\"",
879 autorule->name, limit->name);
880 return (-1);
881 }
882 if (mimic_real_config)
883 limit_inherit(limit);
884 }
885 # endif
886 # ifdef WITH_THRESHOLDS
887 STAILQ_FOREACH(threshold, &autorule->thresholds, link) {
888 if (check_worktime_subset(autorule->worktime_rule,
889 threshold->worktime) < 0) {
890 logconfe("autorule %s, threshold %s: "
891 "threshold's \"worktime\" must be a "
892 "subset of autorule's worktime_rule",
893 autorule->name, threshold->name);
894 return (-1);
895 }
896 if (mimic_real_config)
897 threshold_inherit(threshold);
898 }
899 # endif
900 }
901 return (0);
902 }
903
904 #else /* !WITH_AUTORULES */
905
906 /* ARGSUSED3 */
907 int
create_rule(const char * mod_name,unsigned int autoruleno,const char * rule_name,const char * rule_info ATTR_UNUSED)908 create_rule(const char *mod_name, unsigned int autoruleno,
909 const char *rule_name, const char *rule_info ATTR_UNUSED)
910 {
911 logmsgx(IPA_LOG_WARNING, "create_rule: module %s tries to create "
912 "rule %s from autorule %u", mod_name, rule_name, autoruleno);
913 logmsgx(IPA_LOG_WARNING, "create_rule: autorules support "
914 "was not compiled");
915 return (-1);
916 }
917
918 int
delete_rule(const char * mod_name,unsigned int ruleno)919 delete_rule(const char *mod_name, unsigned int ruleno)
920 {
921 logmsgx(IPA_LOG_ERR, "delete_rule: module %s tries to delete "
922 "rule %u", mod_name, ruleno);
923 logmsgx(IPA_LOG_ERR, "delete_rule: autorules support "
924 "was not compiled");
925 return (-1);
926 }
927 #endif /* WITH_AUTORULES */
928