github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/internal/procfs/procfs_linux.go (about) 1 package procfs 2 3 /* 4 Copyright 2015 The Kubernetes Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 import ( 20 "bytes" 21 "fmt" 22 "io" 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 "regexp" 27 "strconv" 28 "strings" 29 "unicode" 30 31 "github.com/sirupsen/logrus" 32 ) 33 34 // PidOf finds process(es) with a specified name (regexp match) 35 // and return their pid(s) 36 func PidOf(name string) ([]int, error) { 37 if len(name) == 0 { 38 return []int{}, fmt.Errorf("name should not be empty") 39 } 40 re, err := regexp.Compile("(^|/)" + name + "$") 41 if err != nil { 42 return []int{}, err 43 } 44 return getPids(re), nil 45 } 46 47 func getPids(re *regexp.Regexp) []int { 48 pids := []int{} 49 50 dirFD, err := os.Open("/proc") 51 if err != nil { 52 return nil 53 } 54 defer dirFD.Close() 55 56 for { 57 // Read a small number at a time in case there are many entries, we don't want to 58 // allocate a lot here. 59 ls, err := dirFD.Readdir(10) 60 if err == io.EOF { 61 break 62 } 63 if err != nil { 64 return nil 65 } 66 67 for _, entry := range ls { 68 if !entry.IsDir() { 69 continue 70 } 71 72 // If the directory is not a number (i.e. not a PID), skip it 73 pid, err := strconv.Atoi(entry.Name()) 74 if err != nil { 75 continue 76 } 77 78 cmdline, err := ioutil.ReadFile(filepath.Join("/proc", entry.Name(), "cmdline")) 79 if err != nil { 80 logrus.Infof("Error reading file %s: %+v", filepath.Join("/proc", entry.Name(), "cmdline"), err) 81 continue 82 } 83 84 // The bytes we read have '\0' as a separator for the command line 85 parts := bytes.SplitN(cmdline, []byte{0}, 2) 86 if len(parts) == 0 { 87 continue 88 } 89 // Split the command line itself we are interested in just the first part 90 exe := strings.FieldsFunc(string(parts[0]), func(c rune) bool { 91 return unicode.IsSpace(c) || c == ':' 92 }) 93 if len(exe) == 0 { 94 continue 95 } 96 // Check if the name of the executable is what we are looking for 97 if re.MatchString(exe[0]) { 98 // Grab the PID from the directory path 99 pids = append(pids, pid) 100 } 101 } 102 } 103 104 return pids 105 }