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  }