github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/osutil/udev/netlink/matcher.go (about) 1 package netlink 2 3 import ( 4 "fmt" 5 "regexp" 6 ) 7 8 type Matcher interface { 9 Evaluate(e UEvent) bool 10 EvaluateAction(a KObjAction) bool 11 EvaluateEnv(e map[string]string) bool 12 Compile() error 13 String() string 14 } 15 16 type RuleDefinition struct { 17 Action *string `json:"action,omitempty"` 18 Env map[string]string `json:"env,omitempty"` 19 rule *rule 20 } 21 22 // Evaluate return true if all condition match uevent and envs in rule exists in uevent 23 func (r RuleDefinition) Evaluate(e UEvent) bool { 24 // Compile if needed 25 if r.rule == nil { 26 if err := r.Compile(); err != nil { 27 return false 28 } 29 } 30 31 return r.EvaluateAction(e.Action) && r.EvaluateEnv(e.Env) 32 } 33 34 // EvaluateAction return true if the action match 35 func (r RuleDefinition) EvaluateAction(a KObjAction) (match bool) { 36 // Compile if needed 37 if r.rule == nil { 38 if err := r.Compile(); err != nil { 39 return false 40 } 41 } 42 if match = (r.rule.Action == nil); !match { 43 match = r.rule.Action.MatchString(a.String()) 44 } 45 return 46 } 47 48 // EvaluateEnv return true if all env match and exists 49 func (r RuleDefinition) EvaluateEnv(e map[string]string) bool { 50 // Compile if needed 51 if r.rule == nil { 52 if err := r.Compile(); err != nil { 53 return false 54 } 55 } 56 return r.rule.Env.Evaluate(e) 57 } 58 59 // Compile prepare rule definition to be able to Evaluate() an UEvent 60 func (r *RuleDefinition) Compile() error { 61 r.rule = &rule{ 62 Env: make(map[string]*regexp.Regexp, 0), 63 } 64 65 if r.Action != nil { 66 action, err := regexp.Compile(*(r.Action)) 67 if err != nil { 68 return err 69 } 70 r.rule.Action = action 71 } 72 73 for k, v := range r.Env { 74 reg, err := regexp.Compile(v) 75 if err != nil { 76 return err 77 } 78 r.rule.Env[k] = reg 79 } 80 return nil 81 } 82 83 func (r RuleDefinition) String() string { 84 return fmt.Sprintf("Action: %v / Env: %+v", r.Action, r.Env) 85 } 86 87 // rule is the compiled version of the RuleDefinition 88 type rule struct { 89 Action *regexp.Regexp 90 Env Env 91 } 92 93 type Env map[string]*regexp.Regexp 94 95 func (e Env) Evaluate(env map[string]string) bool { 96 foundEnv := (len(e) == 0) 97 for envName, reg := range e { 98 foundEnv = false 99 for k, v := range env { 100 if k == envName { 101 foundEnv = true 102 if !reg.MatchString(v) { 103 return false 104 } 105 } 106 } 107 if !foundEnv { 108 return false 109 } 110 } 111 112 return foundEnv 113 114 } 115 116 // RuleDefinitions is like chained rule with OR operator 117 type RuleDefinitions struct { 118 Rules []RuleDefinition 119 } 120 121 func (rs *RuleDefinitions) AddRule(r RuleDefinition) { 122 rs.Rules = append(rs.Rules, r) 123 } 124 125 func (rs *RuleDefinitions) Compile() error { 126 for _, r := range rs.Rules { 127 if err := r.Compile(); err != nil { 128 return err 129 } 130 } 131 return nil 132 } 133 134 func (rs RuleDefinitions) Evaluate(e UEvent) bool { 135 for _, r := range rs.Rules { 136 if r.Evaluate(e) { 137 return true 138 } 139 } 140 return false 141 } 142 143 // EvaluateAction return true if the action match 144 func (rs RuleDefinitions) EvaluateAction(a KObjAction) (match bool) { 145 for _, r := range rs.Rules { 146 if r.EvaluateAction(a) { 147 return true 148 } 149 } 150 return false 151 } 152 153 // EvaluateEnv return true if almost one env match all regexp 154 func (rs RuleDefinitions) EvaluateEnv(e map[string]string) bool { 155 for _, r := range rs.Rules { 156 if r.EvaluateEnv(e) { 157 return true 158 } 159 } 160 return false 161 } 162 163 func (rs RuleDefinitions) String() string { 164 output := "" 165 for _, v := range rs.Rules { 166 output += "- " + v.String() + "\n" 167 } 168 return output 169 }