github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/prometheus/procfs/proc.go (about)

     1  // Copyright 2018 The Prometheus Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package procfs
    15  
    16  import (
    17  	"bytes"
    18  	"fmt"
    19  	"io/ioutil"
    20  	"os"
    21  	"strconv"
    22  	"strings"
    23  )
    24  
    25  // Proc provides information about a running process.
    26  type Proc struct {
    27  	// The process ID.
    28  	PID int
    29  
    30  	fs FS
    31  }
    32  
    33  // Procs represents a list of Proc structs.
    34  type Procs []Proc
    35  
    36  func (p Procs) Len() int           { return len(p) }
    37  func (p Procs) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
    38  func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID }
    39  
    40  // Self returns a process for the current process read via /proc/self.
    41  func Self() (Proc, error) {
    42  	fs, err := NewFS(DefaultMountPoint)
    43  	if err != nil {
    44  		return Proc{}, err
    45  	}
    46  	return fs.Self()
    47  }
    48  
    49  // NewProc returns a process for the given pid under /proc.
    50  func NewProc(pid int) (Proc, error) {
    51  	fs, err := NewFS(DefaultMountPoint)
    52  	if err != nil {
    53  		return Proc{}, err
    54  	}
    55  	return fs.NewProc(pid)
    56  }
    57  
    58  // AllProcs returns a list of all currently available processes under /proc.
    59  func AllProcs() (Procs, error) {
    60  	fs, err := NewFS(DefaultMountPoint)
    61  	if err != nil {
    62  		return Procs{}, err
    63  	}
    64  	return fs.AllProcs()
    65  }
    66  
    67  // Self returns a process for the current process.
    68  func (fs FS) Self() (Proc, error) {
    69  	p, err := os.Readlink(fs.Path("self"))
    70  	if err != nil {
    71  		return Proc{}, err
    72  	}
    73  	pid, err := strconv.Atoi(strings.Replace(p, string(fs), "", -1))
    74  	if err != nil {
    75  		return Proc{}, err
    76  	}
    77  	return fs.NewProc(pid)
    78  }
    79  
    80  // NewProc returns a process for the given pid.
    81  func (fs FS) NewProc(pid int) (Proc, error) {
    82  	if _, err := os.Stat(fs.Path(strconv.Itoa(pid))); err != nil {
    83  		return Proc{}, err
    84  	}
    85  	return Proc{PID: pid, fs: fs}, nil
    86  }
    87  
    88  // AllProcs returns a list of all currently available processes.
    89  func (fs FS) AllProcs() (Procs, error) {
    90  	d, err := os.Open(fs.Path())
    91  	if err != nil {
    92  		return Procs{}, err
    93  	}
    94  	defer d.Close()
    95  
    96  	names, err := d.Readdirnames(-1)
    97  	if err != nil {
    98  		return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err)
    99  	}
   100  
   101  	p := Procs{}
   102  	for _, n := range names {
   103  		pid, err := strconv.ParseInt(n, 10, 64)
   104  		if err != nil {
   105  			continue
   106  		}
   107  		p = append(p, Proc{PID: int(pid), fs: fs})
   108  	}
   109  
   110  	return p, nil
   111  }
   112  
   113  // CmdLine returns the command line of a process.
   114  func (p Proc) CmdLine() ([]string, error) {
   115  	f, err := os.Open(p.path("cmdline"))
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	defer f.Close()
   120  
   121  	data, err := ioutil.ReadAll(f)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	if len(data) < 1 {
   127  		return []string{}, nil
   128  	}
   129  
   130  	return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil
   131  }
   132  
   133  // Comm returns the command name of a process.
   134  func (p Proc) Comm() (string, error) {
   135  	f, err := os.Open(p.path("comm"))
   136  	if err != nil {
   137  		return "", err
   138  	}
   139  	defer f.Close()
   140  
   141  	data, err := ioutil.ReadAll(f)
   142  	if err != nil {
   143  		return "", err
   144  	}
   145  
   146  	return strings.TrimSpace(string(data)), nil
   147  }
   148  
   149  // Executable returns the absolute path of the executable command of a process.
   150  func (p Proc) Executable() (string, error) {
   151  	exe, err := os.Readlink(p.path("exe"))
   152  	if os.IsNotExist(err) {
   153  		return "", nil
   154  	}
   155  
   156  	return exe, err
   157  }
   158  
   159  // Cwd returns the absolute path to the current working directory of the process.
   160  func (p Proc) Cwd() (string, error) {
   161  	wd, err := os.Readlink(p.path("cwd"))
   162  	if os.IsNotExist(err) {
   163  		return "", nil
   164  	}
   165  
   166  	return wd, err
   167  }
   168  
   169  // RootDir returns the absolute path to the process's root directory (as set by chroot)
   170  func (p Proc) RootDir() (string, error) {
   171  	rdir, err := os.Readlink(p.path("root"))
   172  	if os.IsNotExist(err) {
   173  		return "", nil
   174  	}
   175  
   176  	return rdir, err
   177  }
   178  
   179  // FileDescriptors returns the currently open file descriptors of a process.
   180  func (p Proc) FileDescriptors() ([]uintptr, error) {
   181  	names, err := p.fileDescriptors()
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  
   186  	fds := make([]uintptr, len(names))
   187  	for i, n := range names {
   188  		fd, err := strconv.ParseInt(n, 10, 32)
   189  		if err != nil {
   190  			return nil, fmt.Errorf("could not parse fd %s: %s", n, err)
   191  		}
   192  		fds[i] = uintptr(fd)
   193  	}
   194  
   195  	return fds, nil
   196  }
   197  
   198  // FileDescriptorTargets returns the targets of all file descriptors of a process.
   199  // If a file descriptor is not a symlink to a file (like a socket), that value will be the empty string.
   200  func (p Proc) FileDescriptorTargets() ([]string, error) {
   201  	names, err := p.fileDescriptors()
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	targets := make([]string, len(names))
   207  
   208  	for i, name := range names {
   209  		target, err := os.Readlink(p.path("fd", name))
   210  		if err == nil {
   211  			targets[i] = target
   212  		}
   213  	}
   214  
   215  	return targets, nil
   216  }
   217  
   218  // FileDescriptorsLen returns the number of currently open file descriptors of
   219  // a process.
   220  func (p Proc) FileDescriptorsLen() (int, error) {
   221  	fds, err := p.fileDescriptors()
   222  	if err != nil {
   223  		return 0, err
   224  	}
   225  
   226  	return len(fds), nil
   227  }
   228  
   229  // MountStats retrieves statistics and configuration for mount points in a
   230  // process's namespace.
   231  func (p Proc) MountStats() ([]*Mount, error) {
   232  	f, err := os.Open(p.path("mountstats"))
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  	defer f.Close()
   237  
   238  	return parseMountStats(f)
   239  }
   240  
   241  func (p Proc) fileDescriptors() ([]string, error) {
   242  	d, err := os.Open(p.path("fd"))
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  	defer d.Close()
   247  
   248  	names, err := d.Readdirnames(-1)
   249  	if err != nil {
   250  		return nil, fmt.Errorf("could not read %s: %s", d.Name(), err)
   251  	}
   252  
   253  	return names, nil
   254  }
   255  
   256  func (p Proc) path(pa ...string) string {
   257  	return p.fs.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...)
   258  }