package netlink import ( "regexp" "strings" ) type Matcher interface { Evaluate(e UEvent) bool EvaluateAction(a KObjAction) bool EvaluateEnv(e map[string]string) bool Compile() error String() string } type RuleDefinition struct { Action *string `json:"action,omitempty"` Env map[string]string `json:"env,omitempty"` rule *rule } // Evaluate return true if all condition match uevent and envs in rule exists in uevent func (r RuleDefinition) Evaluate(e UEvent) bool { // Compile if needed if r.rule == nil { if err := r.Compile(); err != nil { return false } } return r.EvaluateAction(e.Action) && r.EvaluateEnv(e.Env) } // EvaluateAction return true if the action match func (r RuleDefinition) EvaluateAction(a KObjAction) bool { // Compile if needed if r.rule == nil { if err := r.Compile(); err != nil { return false } } if r.rule.Action == nil { return true } return r.rule.Action.MatchString(a.String()) } // EvaluateEnv return true if all env match and exists func (r RuleDefinition) EvaluateEnv(e map[string]string) bool { // Compile if needed if r.rule == nil { if err := r.Compile(); err != nil { return false } } return r.rule.Env.Evaluate(e) } // Compile prepare rule definition to be able to Evaluate() an UEvent func (r *RuleDefinition) Compile() error { r.rule = &rule{ Env: make(map[string]*regexp.Regexp), } if r.Action != nil { action, err := regexp.Compile(*(r.Action)) if err != nil { return err } r.rule.Action = action } for k, v := range r.Env { reg, err := regexp.Compile(v) if err != nil { return err } r.rule.Env[k] = reg } return nil } func (r RuleDefinition) String() string { b := strings.Builder{} b.WriteString("ruledef ( ") if r.Action == nil && len(r.Env) == 0 { b.WriteString("empty") } else { if r.Action != nil { b.WriteString("action=") b.WriteString(*r.Action) b.WriteRune(' ') } for k, v := range r.Env { b.WriteString("env.") b.WriteString(k) b.WriteRune('=') b.WriteString(v) b.WriteRune(' ') } } b.WriteString(")") return b.String() } // rule is the compiled version of the RuleDefinition type rule struct { Action *regexp.Regexp Env Env } type Env map[string]*regexp.Regexp func (e Env) Evaluate(env map[string]string) bool { foundEnv := (len(e) == 0) for envName, reg := range e { foundEnv = false for k, v := range env { if k == envName { foundEnv = true if !reg.MatchString(v) { return false } break } } if !foundEnv { return false } } return foundEnv } // RuleDefinitions is like chained rule with OR operator type RuleDefinitions struct { Rules []RuleDefinition } func (rs *RuleDefinitions) AddRule(r RuleDefinition) { rs.Rules = append(rs.Rules, r) } func (rs *RuleDefinitions) Compile() error { for _, r := range rs.Rules { if err := r.Compile(); err != nil { return err } } return nil } func (rs RuleDefinitions) Evaluate(e UEvent) bool { for _, r := range rs.Rules { if r.Evaluate(e) { return true } } return false } // EvaluateAction return true if the action match func (rs RuleDefinitions) EvaluateAction(a KObjAction) (match bool) { for _, r := range rs.Rules { if r.EvaluateAction(a) { return true } } return false } // EvaluateEnv return true if almost one env match all regexp func (rs RuleDefinitions) EvaluateEnv(e map[string]string) bool { for _, r := range rs.Rules { if r.EvaluateEnv(e) { return true } } return false } func (rs RuleDefinitions) String() string { output := "" for _, v := range rs.Rules { output += "- " + v.String() + "\n" } return output }