...

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

Documentation: github.com/shirou/gopsutil/process

     1  // +build openbsd
     2  
     3  package process
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	"encoding/binary"
     9  	"fmt"
    10  	"io"
    11  	"os/exec"
    12  	"path/filepath"
    13  	"strconv"
    14  	"strings"
    15  	"unsafe"
    16  
    17  	cpu "github.com/shirou/gopsutil/cpu"
    18  	"github.com/shirou/gopsutil/internal/common"
    19  	mem "github.com/shirou/gopsutil/mem"
    20  	net "github.com/shirou/gopsutil/net"
    21  	"golang.org/x/sys/unix"
    22  )
    23  
    24  func pidsWithContext(ctx context.Context) ([]int32, error) {
    25  	var ret []int32
    26  	procs, err := ProcessesWithContext(ctx)
    27  	if err != nil {
    28  		return ret, nil
    29  	}
    30  
    31  	for _, p := range procs {
    32  		ret = append(ret, p.Pid)
    33  	}
    34  
    35  	return ret, nil
    36  }
    37  
    38  func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
    39  	k, err := p.getKProc()
    40  	if err != nil {
    41  		return 0, err
    42  	}
    43  
    44  	return k.Ppid, nil
    45  }
    46  
    47  func (p *Process) NameWithContext(ctx context.Context) (string, error) {
    48  	k, err := p.getKProc()
    49  	if err != nil {
    50  		return "", err
    51  	}
    52  	name := common.IntToString(k.Comm[:])
    53  
    54  	if len(name) >= 15 {
    55  		cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
    56  		if err != nil {
    57  			return "", err
    58  		}
    59  		if len(cmdlineSlice) > 0 {
    60  			extendedName := filepath.Base(cmdlineSlice[0])
    61  			if strings.HasPrefix(extendedName, p.name) {
    62  				name = extendedName
    63  			} else {
    64  				name = cmdlineSlice[0]
    65  			}
    66  		}
    67  	}
    68  
    69  	return name, nil
    70  }
    71  
    72  func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
    73  	return "", common.ErrNotImplementedError
    74  }
    75  
    76  func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
    77  	mib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv}
    78  	buf, _, err := common.CallSyscall(mib)
    79  
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	/* From man sysctl(2):
    85  	The buffer pointed to by oldp is filled with an array of char
    86  	pointers followed by the strings themselves. The last char
    87  	pointer is a NULL pointer. */
    88  	var strParts []string
    89  	r := bytes.NewReader(buf)
    90  	baseAddr := uintptr(unsafe.Pointer(&buf[0]))
    91  	for {
    92  		argvp, err := readPtr(r)
    93  		if err != nil {
    94  			return nil, err
    95  		}
    96  		if argvp == 0 { // check for a NULL pointer
    97  			break
    98  		}
    99  		offset := argvp - baseAddr
   100  		length := uintptr(bytes.IndexByte(buf[offset:], 0))
   101  		str := string(buf[offset : offset+length])
   102  		strParts = append(strParts, str)
   103  	}
   104  
   105  	return strParts, nil
   106  }
   107  
   108  // readPtr reads a pointer data from a given reader. WARNING: only little
   109  // endian architectures are supported.
   110  func readPtr(r io.Reader) (uintptr, error) {
   111  	switch sizeofPtr {
   112  	case 4:
   113  		var p uint32
   114  		if err := binary.Read(r, binary.LittleEndian, &p); err != nil {
   115  			return 0, err
   116  		}
   117  		return uintptr(p), nil
   118  	case 8:
   119  		var p uint64
   120  		if err := binary.Read(r, binary.LittleEndian, &p); err != nil {
   121  			return 0, err
   122  		}
   123  		return uintptr(p), nil
   124  	default:
   125  		return 0, fmt.Errorf("unsupported pointer size")
   126  	}
   127  }
   128  
   129  func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
   130  	argv, err := p.CmdlineSliceWithContext(ctx)
   131  	if err != nil {
   132  		return "", err
   133  	}
   134  	return strings.Join(argv, " "), nil
   135  }
   136  
   137  func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
   138  	return 0, common.ErrNotImplementedError
   139  }
   140  
   141  func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
   142  	return nil, common.ErrNotImplementedError
   143  }
   144  
   145  func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
   146  	k, err := p.getKProc()
   147  	if err != nil {
   148  		return "", err
   149  	}
   150  	var s string
   151  	switch k.Stat {
   152  	case SIDL:
   153  	case SRUN:
   154  	case SONPROC:
   155  		s = "R"
   156  	case SSLEEP:
   157  		s = "S"
   158  	case SSTOP:
   159  		s = "T"
   160  	case SDEAD:
   161  		s = "Z"
   162  	}
   163  
   164  	return s, nil
   165  }
   166  
   167  func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
   168  	// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
   169  	pid := p.Pid
   170  	ps, err := exec.LookPath("ps")
   171  	if err != nil {
   172  		return false, err
   173  	}
   174  	out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", strconv.Itoa(int(pid)))
   175  	if err != nil {
   176  		return false, err
   177  	}
   178  	return strings.IndexByte(string(out), '+') != -1, nil
   179  }
   180  
   181  func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
   182  	k, err := p.getKProc()
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	uids := make([]int32, 0, 3)
   188  
   189  	uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid))
   190  
   191  	return uids, nil
   192  }
   193  
   194  func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
   195  	k, err := p.getKProc()
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	gids := make([]int32, 0, 3)
   201  	gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid))
   202  
   203  	return gids, nil
   204  }
   205  
   206  func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) {
   207  	k, err := p.getKProc()
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	groups := make([]int32, k.Ngroups)
   213  	for i := int16(0); i < k.Ngroups; i++ {
   214  		groups[i] = int32(k.Groups[i])
   215  	}
   216  
   217  	return groups, nil
   218  }
   219  
   220  func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
   221  	k, err := p.getKProc()
   222  	if err != nil {
   223  		return "", err
   224  	}
   225  
   226  	ttyNr := uint64(k.Tdev)
   227  
   228  	termmap, err := getTerminalMap()
   229  	if err != nil {
   230  		return "", err
   231  	}
   232  
   233  	return termmap[ttyNr], nil
   234  }
   235  
   236  func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
   237  	k, err := p.getKProc()
   238  	if err != nil {
   239  		return 0, err
   240  	}
   241  	return int32(k.Nice), nil
   242  }
   243  
   244  func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
   245  	k, err := p.getKProc()
   246  	if err != nil {
   247  		return nil, err
   248  	}
   249  	return &IOCountersStat{
   250  		ReadCount:  uint64(k.Uru_inblock),
   251  		WriteCount: uint64(k.Uru_oublock),
   252  	}, nil
   253  }
   254  
   255  func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
   256  	/* not supported, just return 1 */
   257  	return 1, nil
   258  }
   259  
   260  func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
   261  	k, err := p.getKProc()
   262  	if err != nil {
   263  		return nil, err
   264  	}
   265  	return &cpu.TimesStat{
   266  		CPU:    "cpu",
   267  		User:   float64(k.Uutime_sec) + float64(k.Uutime_usec)/1000000,
   268  		System: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000,
   269  	}, nil
   270  }
   271  
   272  func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
   273  	k, err := p.getKProc()
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  	pageSize, err := mem.GetPageSizeWithContext(ctx)
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  
   282  	return &MemoryInfoStat{
   283  		RSS: uint64(k.Vm_rssize) * pageSize,
   284  		VMS: uint64(k.Vm_tsize) + uint64(k.Vm_dsize) +
   285  			uint64(k.Vm_ssize),
   286  	}, nil
   287  }
   288  
   289  func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
   290  	pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  	ret := make([]*Process, 0, len(pids))
   295  	for _, pid := range pids {
   296  		np, err := NewProcessWithContext(ctx, pid)
   297  		if err != nil {
   298  			return nil, err
   299  		}
   300  		ret = append(ret, np)
   301  	}
   302  	return ret, nil
   303  }
   304  
   305  func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
   306  	return nil, common.ErrNotImplementedError
   307  }
   308  
   309  func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) {
   310  	return nil, common.ErrNotImplementedError
   311  }
   312  
   313  func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
   314  	results := []*Process{}
   315  
   316  	buf, length, err := callKernProcSyscall(KernProcAll, 0)
   317  
   318  	if err != nil {
   319  		return results, err
   320  	}
   321  
   322  	// get kinfo_proc size
   323  	count := int(length / uint64(sizeOfKinfoProc))
   324  
   325  	// parse buf to procs
   326  	for i := 0; i < count; i++ {
   327  		b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
   328  		k, err := parseKinfoProc(b)
   329  		if err != nil {
   330  			continue
   331  		}
   332  		p, err := NewProcessWithContext(ctx, int32(k.Pid))
   333  		if err != nil {
   334  			continue
   335  		}
   336  
   337  		results = append(results, p)
   338  	}
   339  
   340  	return results, nil
   341  }
   342  
   343  func (p *Process) getKProc() (*KinfoProc, error) {
   344  	buf, length, err := callKernProcSyscall(KernProcPID, p.Pid)
   345  	if err != nil {
   346  		return nil, err
   347  	}
   348  	if length != sizeOfKinfoProc {
   349  		return nil, err
   350  	}
   351  
   352  	k, err := parseKinfoProc(buf)
   353  	if err != nil {
   354  		return nil, err
   355  	}
   356  	return &k, nil
   357  }
   358  
   359  func callKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) {
   360  	mib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0}
   361  	mibptr := unsafe.Pointer(&mib[0])
   362  	miblen := uint64(len(mib))
   363  	length := uint64(0)
   364  	_, _, err := unix.Syscall6(
   365  		unix.SYS___SYSCTL,
   366  		uintptr(mibptr),
   367  		uintptr(miblen),
   368  		0,
   369  		uintptr(unsafe.Pointer(&length)),
   370  		0,
   371  		0)
   372  	if err != 0 {
   373  		return nil, length, err
   374  	}
   375  
   376  	count := int32(length / uint64(sizeOfKinfoProc))
   377  	mib = []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, count}
   378  	mibptr = unsafe.Pointer(&mib[0])
   379  	miblen = uint64(len(mib))
   380  	// get proc info itself
   381  	buf := make([]byte, length)
   382  	_, _, err = unix.Syscall6(
   383  		unix.SYS___SYSCTL,
   384  		uintptr(mibptr),
   385  		uintptr(miblen),
   386  		uintptr(unsafe.Pointer(&buf[0])),
   387  		uintptr(unsafe.Pointer(&length)),
   388  		0,
   389  		0)
   390  	if err != 0 {
   391  		return buf, length, err
   392  	}
   393  
   394  	return buf, length, nil
   395  }
   396  

View as plain text