...
1
2
3
4
19
20 package procfs
21
22 import (
23 "bytes"
24 "fmt"
25 "io"
26 "os"
27 "path"
28 "path/filepath"
29 "regexp"
30 "strconv"
31 "strings"
32 "syscall"
33 "unicode"
34
35 utilerrors "k8s.io/apimachinery/pkg/util/errors"
36 "k8s.io/klog/v2"
37 )
38
39
40 type ProcFS struct{}
41
42 func containerNameFromProcCgroup(content string) (string, error) {
43 lines := strings.Split(content, "\n")
44 for _, line := range lines {
45 entries := strings.SplitN(line, ":", 3)
46 if len(entries) == 3 && entries[1] == "devices" {
47 return strings.TrimSpace(entries[2]), nil
48 }
49 }
50 return "", fmt.Errorf("could not find devices cgroup location")
51 }
52
53
54
55
56 func (pfs *ProcFS) GetFullContainerName(pid int) (string, error) {
57 filePath := path.Join("/proc", strconv.Itoa(pid), "cgroup")
58 content, err := os.ReadFile(filePath)
59 if err != nil {
60 if os.IsNotExist(err) {
61 return "", os.ErrNotExist
62 }
63 return "", err
64 }
65 return containerNameFromProcCgroup(string(content))
66 }
67
68
69
70 func PKill(name string, sig syscall.Signal) error {
71 if len(name) == 0 {
72 return fmt.Errorf("name should not be empty")
73 }
74 re, err := regexp.Compile(name)
75 if err != nil {
76 return err
77 }
78 pids := getPids(re)
79 if len(pids) == 0 {
80 return fmt.Errorf("unable to fetch pids for process name : %q", name)
81 }
82 errList := []error{}
83 for _, pid := range pids {
84 if err = syscall.Kill(pid, sig); err != nil {
85 errList = append(errList, err)
86 }
87 }
88 return utilerrors.NewAggregate(errList)
89 }
90
91
92
93 func PidOf(name string) ([]int, error) {
94 if len(name) == 0 {
95 return []int{}, fmt.Errorf("name should not be empty")
96 }
97 re, err := regexp.Compile("(^|/)" + name + "$")
98 if err != nil {
99 return []int{}, err
100 }
101 return getPids(re), nil
102 }
103
104 func getPids(re *regexp.Regexp) []int {
105 pids := []int{}
106
107 dirFD, err := os.Open("/proc")
108 if err != nil {
109 return nil
110 }
111 defer dirFD.Close()
112
113 for {
114
115
116 ls, err := dirFD.Readdir(10)
117 if err == io.EOF {
118 break
119 }
120 if err != nil {
121 return nil
122 }
123
124 for _, entry := range ls {
125 if !entry.IsDir() {
126 continue
127 }
128
129
130 pid, err := strconv.Atoi(entry.Name())
131 if err != nil {
132 continue
133 }
134
135 cmdline, err := os.ReadFile(filepath.Join("/proc", entry.Name(), "cmdline"))
136 if err != nil {
137 klog.V(4).Infof("Error reading file %s: %+v", filepath.Join("/proc", entry.Name(), "cmdline"), err)
138 continue
139 }
140
141
142 parts := bytes.SplitN(cmdline, []byte{0}, 2)
143 if len(parts) == 0 {
144 continue
145 }
146
147 exe := strings.FieldsFunc(string(parts[0]), func(c rune) bool {
148 return unicode.IsSpace(c) || c == ':'
149 })
150 if len(exe) == 0 {
151 continue
152 }
153
154 if re.MatchString(exe[0]) {
155
156 pids = append(pids, pid)
157 }
158 }
159 }
160
161 return pids
162 }
163
View as plain text