github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/process/process_openbsd.go (about)

     1  //go:build openbsd
     2  // +build openbsd
     3  
     4  package process
     5  
     6  import (
     7  	"C"
     8  	"bytes"
     9  	"context"
    10  	"encoding/binary"
    11  	"os/exec"
    12  	"path/filepath"
    13  	"strconv"
    14  	"strings"
    15  	"unsafe"
    16  
    17  	"github.com/gofiber/fiber/v2/internal/gopsutil/common"
    18  	cpu "github.com/gofiber/fiber/v2/internal/gopsutil/cpu"
    19  	mem "github.com/gofiber/fiber/v2/internal/gopsutil/mem"
    20  	net "github.com/gofiber/fiber/v2/internal/gopsutil/net"
    21  	"golang.org/x/sys/unix"
    22  )
    23  
    24  // MemoryInfoExStat is different between OSes
    25  type MemoryInfoExStat struct {
    26  }
    27  
    28  type MemoryMapsStat struct {
    29  }
    30  
    31  func pidsWithContext(ctx context.Context) ([]int32, error) {
    32  	var ret []int32
    33  	procs, err := Processes()
    34  	if err != nil {
    35  		return ret, nil
    36  	}
    37  
    38  	for _, p := range procs {
    39  		ret = append(ret, p.Pid)
    40  	}
    41  
    42  	return ret, nil
    43  }
    44  
    45  func (p *Process) Ppid() (int32, error) {
    46  	return p.PpidWithContext(context.Background())
    47  }
    48  
    49  func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
    50  	k, err := p.getKProc()
    51  	if err != nil {
    52  		return 0, err
    53  	}
    54  
    55  	return k.Ppid, nil
    56  }
    57  func (p *Process) Name() (string, error) {
    58  	return p.NameWithContext(context.Background())
    59  }
    60  
    61  func (p *Process) NameWithContext(ctx context.Context) (string, error) {
    62  	k, err := p.getKProc()
    63  	if err != nil {
    64  		return "", err
    65  	}
    66  	name := common.IntToString(k.Comm[:])
    67  
    68  	if len(name) >= 15 {
    69  		cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
    70  		if err != nil {
    71  			return "", err
    72  		}
    73  		if len(cmdlineSlice) > 0 {
    74  			extendedName := filepath.Base(cmdlineSlice[0])
    75  			if strings.HasPrefix(extendedName, p.name) {
    76  				name = extendedName
    77  			} else {
    78  				name = cmdlineSlice[0]
    79  			}
    80  		}
    81  	}
    82  
    83  	return name, nil
    84  }
    85  func (p *Process) Tgid() (int32, error) {
    86  	return 0, common.ErrNotImplementedError
    87  }
    88  func (p *Process) Exe() (string, error) {
    89  	return p.ExeWithContext(context.Background())
    90  }
    91  
    92  func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
    93  	return "", common.ErrNotImplementedError
    94  }
    95  
    96  func (p *Process) CmdlineSlice() ([]string, error) {
    97  	return p.CmdlineSliceWithContext(context.Background())
    98  }
    99  
   100  func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
   101  	mib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv}
   102  	buf, _, err := common.CallSyscall(mib)
   103  
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  
   108  	argc := 0
   109  	argvp := unsafe.Pointer(&buf[0])
   110  	argv := *(**C.char)(unsafe.Pointer(argvp))
   111  	size := unsafe.Sizeof(argv)
   112  	var strParts []string
   113  
   114  	for argv != nil {
   115  		strParts = append(strParts, C.GoString(argv))
   116  
   117  		argc++
   118  		argv = *(**C.char)(unsafe.Pointer(uintptr(argvp) + uintptr(argc)*size))
   119  	}
   120  	return strParts, nil
   121  }
   122  
   123  func (p *Process) Cmdline() (string, error) {
   124  	return p.CmdlineWithContext(context.Background())
   125  }
   126  
   127  func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
   128  	argv, err := p.CmdlineSlice()
   129  	if err != nil {
   130  		return "", err
   131  	}
   132  	return strings.Join(argv, " "), nil
   133  }
   134  
   135  func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
   136  	return 0, common.ErrNotImplementedError
   137  }
   138  func (p *Process) Cwd() (string, error) {
   139  	return p.CwdWithContext(context.Background())
   140  }
   141  
   142  func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
   143  	return "", common.ErrNotImplementedError
   144  }
   145  func (p *Process) Parent() (*Process, error) {
   146  	return p.ParentWithContext(context.Background())
   147  }
   148  
   149  func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
   150  	return p, common.ErrNotImplementedError
   151  }
   152  func (p *Process) Status() (string, error) {
   153  	return p.StatusWithContext(context.Background())
   154  }
   155  
   156  func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
   157  	k, err := p.getKProc()
   158  	if err != nil {
   159  		return "", err
   160  	}
   161  	var s string
   162  	switch k.Stat {
   163  	case SIDL:
   164  	case SRUN:
   165  	case SONPROC:
   166  		s = "R"
   167  	case SSLEEP:
   168  		s = "S"
   169  	case SSTOP:
   170  		s = "T"
   171  	case SDEAD:
   172  		s = "Z"
   173  	}
   174  
   175  	return s, nil
   176  }
   177  func (p *Process) Foreground() (bool, error) {
   178  	return p.ForegroundWithContext(context.Background())
   179  }
   180  
   181  func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
   182  	// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
   183  	pid := p.Pid
   184  	ps, err := exec.LookPath("ps")
   185  	if err != nil {
   186  		return false, err
   187  	}
   188  	out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", strconv.Itoa(int(pid)))
   189  	if err != nil {
   190  		return false, err
   191  	}
   192  	return strings.IndexByte(string(out), '+') != -1, nil
   193  }
   194  func (p *Process) Uids() ([]int32, error) {
   195  	return p.UidsWithContext(context.Background())
   196  }
   197  
   198  func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
   199  	k, err := p.getKProc()
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  
   204  	uids := make([]int32, 0, 3)
   205  
   206  	uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid))
   207  
   208  	return uids, nil
   209  }
   210  func (p *Process) Gids() ([]int32, error) {
   211  	return p.GidsWithContext(context.Background())
   212  }
   213  
   214  func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
   215  	k, err := p.getKProc()
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  
   220  	gids := make([]int32, 0, 3)
   221  	gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid))
   222  
   223  	return gids, nil
   224  }
   225  func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) {
   226  	k, err := p.getKProc()
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  
   231  	return k.Groups, nil
   232  }
   233  func (p *Process) Terminal() (string, error) {
   234  	return p.TerminalWithContext(context.Background())
   235  }
   236  
   237  func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
   238  	k, err := p.getKProc()
   239  	if err != nil {
   240  		return "", err
   241  	}
   242  
   243  	ttyNr := uint64(k.Tdev)
   244  
   245  	termmap, err := getTerminalMap()
   246  	if err != nil {
   247  		return "", err
   248  	}
   249  
   250  	return termmap[ttyNr], nil
   251  }
   252  func (p *Process) Nice() (int32, error) {
   253  	return p.NiceWithContext(context.Background())
   254  }
   255  
   256  func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
   257  	k, err := p.getKProc()
   258  	if err != nil {
   259  		return 0, err
   260  	}
   261  	return int32(k.Nice), nil
   262  }
   263  func (p *Process) IOnice() (int32, error) {
   264  	return p.IOniceWithContext(context.Background())
   265  }
   266  
   267  func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
   268  	return 0, common.ErrNotImplementedError
   269  }
   270  func (p *Process) Rlimit() ([]RlimitStat, error) {
   271  	return p.RlimitWithContext(context.Background())
   272  }
   273  
   274  func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
   275  	var rlimit []RlimitStat
   276  	return rlimit, common.ErrNotImplementedError
   277  }
   278  func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
   279  	return p.RlimitUsageWithContext(context.Background(), gatherUsed)
   280  }
   281  
   282  func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
   283  	var rlimit []RlimitStat
   284  	return rlimit, common.ErrNotImplementedError
   285  }
   286  func (p *Process) IOCounters() (*IOCountersStat, error) {
   287  	return p.IOCountersWithContext(context.Background())
   288  }
   289  
   290  func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
   291  	k, err := p.getKProc()
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  	return &IOCountersStat{
   296  		ReadCount:  uint64(k.Uru_inblock),
   297  		WriteCount: uint64(k.Uru_oublock),
   298  	}, nil
   299  }
   300  func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
   301  	return p.NumCtxSwitchesWithContext(context.Background())
   302  }
   303  
   304  func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
   305  	return nil, common.ErrNotImplementedError
   306  }
   307  func (p *Process) NumFDs() (int32, error) {
   308  	return p.NumFDsWithContext(context.Background())
   309  }
   310  
   311  func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
   312  	return 0, common.ErrNotImplementedError
   313  }
   314  func (p *Process) NumThreads() (int32, error) {
   315  	return p.NumThreadsWithContext(context.Background())
   316  }
   317  
   318  func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
   319  	/* not supported, just return 1 */
   320  	return 1, nil
   321  }
   322  func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
   323  	return p.ThreadsWithContext(context.Background())
   324  }
   325  
   326  func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
   327  	ret := make(map[int32]*cpu.TimesStat)
   328  	return ret, common.ErrNotImplementedError
   329  }
   330  func (p *Process) Times() (*cpu.TimesStat, error) {
   331  	return p.TimesWithContext(context.Background())
   332  }
   333  
   334  func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
   335  	k, err := p.getKProc()
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  	return &cpu.TimesStat{
   340  		CPU:    "cpu",
   341  		User:   float64(k.Uutime_sec) + float64(k.Uutime_usec)/1000000,
   342  		System: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000,
   343  	}, nil
   344  }
   345  func (p *Process) CPUAffinity() ([]int32, error) {
   346  	return p.CPUAffinityWithContext(context.Background())
   347  }
   348  
   349  func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
   350  	return nil, common.ErrNotImplementedError
   351  }
   352  func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
   353  	return p.MemoryInfoWithContext(context.Background())
   354  }
   355  
   356  func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
   357  	k, err := p.getKProc()
   358  	if err != nil {
   359  		return nil, err
   360  	}
   361  	pageSize, err := mem.GetPageSize()
   362  	if err != nil {
   363  		return nil, err
   364  	}
   365  
   366  	return &MemoryInfoStat{
   367  		RSS: uint64(k.Vm_rssize) * pageSize,
   368  		VMS: uint64(k.Vm_tsize) + uint64(k.Vm_dsize) +
   369  			uint64(k.Vm_ssize),
   370  	}, nil
   371  }
   372  func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
   373  	return p.MemoryInfoExWithContext(context.Background())
   374  }
   375  
   376  func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
   377  	return nil, common.ErrNotImplementedError
   378  }
   379  
   380  func (p *Process) PageFaults() (*PageFaultsStat, error) {
   381  	return p.PageFaultsWithContext(context.Background())
   382  }
   383  
   384  func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
   385  	return nil, common.ErrNotImplementedError
   386  }
   387  
   388  func (p *Process) Children() ([]*Process, error) {
   389  	return p.ChildrenWithContext(context.Background())
   390  }
   391  
   392  func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
   393  	pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  	ret := make([]*Process, 0, len(pids))
   398  	for _, pid := range pids {
   399  		np, err := NewProcess(pid)
   400  		if err != nil {
   401  			return nil, err
   402  		}
   403  		ret = append(ret, np)
   404  	}
   405  	return ret, nil
   406  }
   407  
   408  func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
   409  	return p.OpenFilesWithContext(context.Background())
   410  }
   411  
   412  func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
   413  	return nil, common.ErrNotImplementedError
   414  }
   415  
   416  func (p *Process) Connections() ([]net.ConnectionStat, error) {
   417  	return p.ConnectionsWithContext(context.Background())
   418  }
   419  
   420  func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
   421  	return nil, common.ErrNotImplementedError
   422  }
   423  
   424  func (p *Process) ConnectionsMax(max int) ([]net.ConnectionStat, error) {
   425  	return p.ConnectionsMaxWithContext(context.Background(), max)
   426  }
   427  
   428  func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) {
   429  	return []net.ConnectionStat{}, common.ErrNotImplementedError
   430  }
   431  
   432  func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
   433  	return p.NetIOCountersWithContext(context.Background(), pernic)
   434  }
   435  
   436  func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
   437  	return nil, common.ErrNotImplementedError
   438  }
   439  
   440  func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
   441  	return p.MemoryMapsWithContext(context.Background(), grouped)
   442  }
   443  
   444  func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
   445  	var ret []MemoryMapsStat
   446  	return &ret, common.ErrNotImplementedError
   447  }
   448  
   449  func Processes() ([]*Process, error) {
   450  	return ProcessesWithContext(context.Background())
   451  }
   452  
   453  func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
   454  	results := []*Process{}
   455  
   456  	buf, length, err := CallKernProcSyscall(KernProcAll, 0)
   457  
   458  	if err != nil {
   459  		return results, err
   460  	}
   461  
   462  	// get kinfo_proc size
   463  	count := int(length / uint64(sizeOfKinfoProc))
   464  
   465  	// parse buf to procs
   466  	for i := 0; i < count; i++ {
   467  		b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
   468  		k, err := parseKinfoProc(b)
   469  		if err != nil {
   470  			continue
   471  		}
   472  		p, err := NewProcess(int32(k.Pid))
   473  		if err != nil {
   474  			continue
   475  		}
   476  
   477  		results = append(results, p)
   478  	}
   479  
   480  	return results, nil
   481  }
   482  
   483  func parseKinfoProc(buf []byte) (KinfoProc, error) {
   484  	var k KinfoProc
   485  	br := bytes.NewReader(buf)
   486  	err := common.Read(br, binary.LittleEndian, &k)
   487  	return k, err
   488  }
   489  
   490  func (p *Process) getKProc() (*KinfoProc, error) {
   491  	return p.getKProcWithContext(context.Background())
   492  }
   493  
   494  func (p *Process) getKProcWithContext(ctx context.Context) (*KinfoProc, error) {
   495  	buf, length, err := CallKernProcSyscall(KernProcPID, p.Pid)
   496  	if err != nil {
   497  		return nil, err
   498  	}
   499  	if length != sizeOfKinfoProc {
   500  		return nil, err
   501  	}
   502  
   503  	k, err := parseKinfoProc(buf)
   504  	if err != nil {
   505  		return nil, err
   506  	}
   507  	return &k, nil
   508  }
   509  
   510  func CallKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) {
   511  	return CallKernProcSyscallWithContext(context.Background(), op, arg)
   512  }
   513  
   514  func CallKernProcSyscallWithContext(ctx context.Context, op int32, arg int32) ([]byte, uint64, error) {
   515  	mib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0}
   516  	mibptr := unsafe.Pointer(&mib[0])
   517  	miblen := uint64(len(mib))
   518  	length := uint64(0)
   519  	_, _, err := unix.Syscall6(
   520  		unix.SYS___SYSCTL,
   521  		uintptr(mibptr),
   522  		uintptr(miblen),
   523  		0,
   524  		uintptr(unsafe.Pointer(&length)),
   525  		0,
   526  		0)
   527  	if err != 0 {
   528  		return nil, length, err
   529  	}
   530  
   531  	count := int32(length / uint64(sizeOfKinfoProc))
   532  	mib = []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, count}
   533  	mibptr = unsafe.Pointer(&mib[0])
   534  	miblen = uint64(len(mib))
   535  	// get proc info itself
   536  	buf := make([]byte, length)
   537  	_, _, err = unix.Syscall6(
   538  		unix.SYS___SYSCTL,
   539  		uintptr(mibptr),
   540  		uintptr(miblen),
   541  		uintptr(unsafe.Pointer(&buf[0])),
   542  		uintptr(unsafe.Pointer(&length)),
   543  		0,
   544  		0)
   545  	if err != 0 {
   546  		return buf, length, err
   547  	}
   548  
   549  	return buf, length, nil
   550  }