1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package process
5
6import (
7	"strings"
8
9	"github.com/keybase/go-ps"
10)
11
12// MatchFn is a process matching function
13type MatchFn func(ps.Process) bool
14
15// Matcher can match a process
16type Matcher struct {
17	match     string
18	matchType MatchType
19	exceptPID int
20	log       Log
21}
22
23// MatchType is how to match
24type MatchType string
25
26const (
27	// PathEqual matches path equals string
28	PathEqual MatchType = "path-equal"
29	// PathContains matches path contains string
30	PathContains MatchType = "path-contains"
31	// PathPrefix matches path has string prefix
32	PathPrefix MatchType = "path-prefix"
33	// ExecutableEqual matches executable name equals string
34	ExecutableEqual MatchType = "executable-equal"
35)
36
37// NewMatcher returns a new matcher
38func NewMatcher(match string, matchType MatchType, log Log) Matcher {
39	return Matcher{match: match, matchType: matchType, log: log}
40}
41
42// ExceptPID will not match specified pid
43func (m *Matcher) ExceptPID(p int) {
44	m.exceptPID = p
45}
46
47func (m Matcher) matchPathFn(pathFn func(path, str string) bool) MatchFn {
48	return func(p ps.Process) bool {
49		if m.exceptPID != 0 && p.Pid() == m.exceptPID {
50			return false
51		}
52		path, err := p.Path()
53		if err != nil {
54			return false
55		}
56		return pathFn(path, m.match)
57	}
58}
59
60func (m Matcher) matchExecutableFn(execFn func(executable, str string) bool) MatchFn {
61	return func(p ps.Process) bool {
62		if m.exceptPID != 0 && p.Pid() == m.exceptPID {
63			return false
64		}
65		return execFn(p.Executable(), m.match)
66	}
67}
68
69// Fn is the matching function
70func (m Matcher) Fn() MatchFn {
71	switch m.matchType {
72	case PathEqual:
73		return m.matchPathFn(func(s, t string) bool { return s == t })
74	case PathContains:
75		return m.matchPathFn(strings.Contains)
76	case PathPrefix:
77		return m.matchPathFn(strings.HasPrefix)
78	case ExecutableEqual:
79		return m.matchExecutableFn(func(s, t string) bool { return s == t })
80	default:
81		return nil
82	}
83}
84