...

Source file src/github.com/shirou/gopsutil/process/process_freebsd.go

Documentation: github.com/shirou/gopsutil/process

     1  // +build freebsd
     2  
     3  package process
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"strconv"
    11  	"strings"
    12  
    13  	cpu "github.com/shirou/gopsutil/cpu"
    14  	"github.com/shirou/gopsutil/internal/common"
    15  	net "github.com/shirou/gopsutil/net"
    16  	"golang.org/x/sys/unix"
    17  )
    18  
    19  func pidsWithContext(ctx context.Context) ([]int32, error) {
    20  	var ret []int32
    21  	procs, err := ProcessesWithContext(ctx)
    22  	if err != nil {
    23  		return ret, nil
    24  	}
    25  
    26  	for _, p := range procs {
    27  		ret = append(ret, p.Pid)
    28  	}
    29  
    30  	return ret, nil
    31  }
    32  
    33  func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
    34  	k, err := p.getKProc()
    35  	if err != nil {
    36  		return 0, err
    37  	}
    38  
    39  	return k.Ppid, nil
    40  }
    41  
    42  func (p *Process) NameWithContext(ctx context.Context) (string, error) {
    43  	k, err := p.getKProc()
    44  	if err != nil {
    45  		return "", err
    46  	}
    47  	name := common.IntToString(k.Comm[:])
    48  
    49  	if len(name) >= 15 {
    50  		cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
    51  		if err != nil {
    52  			return "", err
    53  		}
    54  		if len(cmdlineSlice) > 0 {
    55  			extendedName := filepath.Base(cmdlineSlice[0])
    56  			if strings.HasPrefix(extendedName, p.name) {
    57  				name = extendedName
    58  			} else {
    59  				name = cmdlineSlice[0]
    60  			}
    61  		}
    62  	}
    63  
    64  	return name, nil
    65  }
    66  
    67  func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
    68  	return "", common.ErrNotImplementedError
    69  }
    70  
    71  func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
    72  	mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
    73  	buf, _, err := common.CallSyscall(mib)
    74  	if err != nil {
    75  		return "", err
    76  	}
    77  	ret := strings.FieldsFunc(string(buf), func(r rune) bool {
    78  		if r == '\u0000' {
    79  			return true
    80  		}
    81  		return false
    82  	})
    83  
    84  	return strings.Join(ret, " "), nil
    85  }
    86  
    87  func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
    88  	mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
    89  	buf, _, err := common.CallSyscall(mib)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	if len(buf) == 0 {
    94  		return nil, nil
    95  	}
    96  	if buf[len(buf)-1] == 0 {
    97  		buf = buf[:len(buf)-1]
    98  	}
    99  	parts := bytes.Split(buf, []byte{0})
   100  	var strParts []string
   101  	for _, p := range parts {
   102  		strParts = append(strParts, string(p))
   103  	}
   104  
   105  	return strParts, nil
   106  }
   107  
   108  func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
   109  	return 0, common.ErrNotImplementedError
   110  }
   111  
   112  func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
   113  	return nil, common.ErrNotImplementedError
   114  }
   115  
   116  func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
   117  	k, err := p.getKProc()
   118  	if err != nil {
   119  		return "", err
   120  	}
   121  	var s string
   122  	switch k.Stat {
   123  	case SIDL:
   124  		s = "I"
   125  	case SRUN:
   126  		s = "R"
   127  	case SSLEEP:
   128  		s = "S"
   129  	case SSTOP:
   130  		s = "T"
   131  	case SZOMB:
   132  		s = "Z"
   133  	case SWAIT:
   134  		s = "W"
   135  	case SLOCK:
   136  		s = "L"
   137  	}
   138  
   139  	return s, nil
   140  }
   141  
   142  func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
   143  	// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
   144  	pid := p.Pid
   145  	ps, err := exec.LookPath("ps")
   146  	if err != nil {
   147  		return false, err
   148  	}
   149  	out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", strconv.Itoa(int(pid)))
   150  	if err != nil {
   151  		return false, err
   152  	}
   153  	return strings.IndexByte(string(out), '+') != -1, nil
   154  }
   155  
   156  func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
   157  	k, err := p.getKProc()
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  
   162  	uids := make([]int32, 0, 3)
   163  
   164  	uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid))
   165  
   166  	return uids, nil
   167  }
   168  
   169  func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
   170  	k, err := p.getKProc()
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	gids := make([]int32, 0, 3)
   176  	gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid))
   177  
   178  	return gids, nil
   179  }
   180  
   181  func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) {
   182  	k, err := p.getKProc()
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	groups := make([]int32, k.Ngroups)
   188  	for i := int16(0); i < k.Ngroups; i++ {
   189  		groups[i] = int32(k.Groups[i])
   190  	}
   191  
   192  	return groups, nil
   193  }
   194  
   195  func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
   196  	k, err := p.getKProc()
   197  	if err != nil {
   198  		return "", err
   199  	}
   200  
   201  	ttyNr := uint64(k.Tdev)
   202  
   203  	termmap, err := getTerminalMap()
   204  	if err != nil {
   205  		return "", err
   206  	}
   207  
   208  	return termmap[ttyNr], nil
   209  }
   210  
   211  func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
   212  	k, err := p.getKProc()
   213  	if err != nil {
   214  		return 0, err
   215  	}
   216  	return int32(k.Nice), nil
   217  }
   218  
   219  func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
   220  	k, err := p.getKProc()
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  	return &IOCountersStat{
   225  		ReadCount:  uint64(k.Rusage.Inblock),
   226  		WriteCount: uint64(k.Rusage.Oublock),
   227  	}, nil
   228  }
   229  
   230  func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
   231  	k, err := p.getKProc()
   232  	if err != nil {
   233  		return 0, err
   234  	}
   235  
   236  	return k.Numthreads, nil
   237  }
   238  
   239  func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
   240  	k, err := p.getKProc()
   241  	if err != nil {
   242  		return nil, err
   243  	}
   244  	return &cpu.TimesStat{
   245  		CPU:    "cpu",
   246  		User:   float64(k.Rusage.Utime.Sec) + float64(k.Rusage.Utime.Usec)/1000000,
   247  		System: float64(k.Rusage.Stime.Sec) + float64(k.Rusage.Stime.Usec)/1000000,
   248  	}, nil
   249  }
   250  
   251  func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
   252  	k, err := p.getKProc()
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  	v, err := unix.Sysctl("vm.stats.vm.v_page_size")
   257  	if err != nil {
   258  		return nil, err
   259  	}
   260  	pageSize := common.LittleEndian.Uint16([]byte(v))
   261  
   262  	return &MemoryInfoStat{
   263  		RSS: uint64(k.Rssize) * uint64(pageSize),
   264  		VMS: uint64(k.Size),
   265  	}, nil
   266  }
   267  
   268  func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
   269  	pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
   270  	if err != nil {
   271  		return nil, err
   272  	}
   273  	ret := make([]*Process, 0, len(pids))
   274  	for _, pid := range pids {
   275  		np, err := NewProcessWithContext(ctx, pid)
   276  		if err != nil {
   277  			return nil, err
   278  		}
   279  		ret = append(ret, np)
   280  	}
   281  	return ret, nil
   282  }
   283  
   284  func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
   285  	return nil, common.ErrNotImplementedError
   286  }
   287  
   288  func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) {
   289  	return nil, common.ErrNotImplementedError
   290  }
   291  
   292  func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
   293  	results := []*Process{}
   294  
   295  	mib := []int32{CTLKern, KernProc, KernProcProc, 0}
   296  	buf, length, err := common.CallSyscall(mib)
   297  	if err != nil {
   298  		return results, err
   299  	}
   300  
   301  	// get kinfo_proc size
   302  	count := int(length / uint64(sizeOfKinfoProc))
   303  
   304  	// parse buf to procs
   305  	for i := 0; i < count; i++ {
   306  		b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
   307  		k, err := parseKinfoProc(b)
   308  		if err != nil {
   309  			continue
   310  		}
   311  		p, err := NewProcessWithContext(ctx, int32(k.Pid))
   312  		if err != nil {
   313  			continue
   314  		}
   315  
   316  		results = append(results, p)
   317  	}
   318  
   319  	return results, nil
   320  }
   321  
   322  func (p *Process) getKProc() (*KinfoProc, error) {
   323  	mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
   324  
   325  	buf, length, err := common.CallSyscall(mib)
   326  	if err != nil {
   327  		return nil, err
   328  	}
   329  	if length != sizeOfKinfoProc {
   330  		return nil, err
   331  	}
   332  
   333  	k, err := parseKinfoProc(buf)
   334  	if err != nil {
   335  		return nil, err
   336  	}
   337  	return &k, nil
   338  }
   339  

View as plain text