//go:build linux || freebsd || openbsd || darwin

package process

import (
	
	
	
	
	
	
	
	
	
	

	

	
)

// POSIX
func getTerminalMap() (map[uint64]string, error) {
	 := make(map[uint64]string)
	var  []string

	,  := os.Open("/dev")
	if  != nil {
		return nil, 
	}
	defer .Close()

	,  := .Readdirnames(-1)
	if  != nil {
		return nil, 
	}
	for ,  := range  {
		if strings.HasPrefix(, "/dev/tty") {
			 = append(, "/dev/tty/"+)
		}
	}

	var  []string
	,  := os.Open("/dev/pts")
	if  != nil {
		, _ = filepath.Glob("/dev/ttyp*")
		if  == nil {
			return nil, 
		}
	}
	defer .Close()

	if  == nil {
		defer .Close()
		,  = .Readdirnames(-1)
		if  != nil {
			return nil, 
		}
		for ,  := range  {
			 = append(, "/dev/pts/"+)
		}
	} else {
		 = 
	}

	for ,  := range  {
		 := unix.Stat_t{}
		if  = unix.Stat(, &);  != nil {
			return nil, 
		}
		 := uint64(.Rdev)
		[] = strings.Replace(, "/dev", "", -1)
	}
	return , nil
}

func ( context.Context,  int32) (bool, error) {
	if  <= 0 {
		return false, fmt.Errorf("invalid pid %v", )
	}
	,  := os.FindProcess(int())
	if  != nil {
		return false, 
	}

	if ,  := os.Stat(common.HostProc());  == nil { // Means that proc filesystem exist
		// Checking PID existence based on existence of /<HOST_PROC>/proc/<PID> folder
		// This covers the case when running inside container with a different process namespace (by default)

		,  := os.Stat(common.HostProc(strconv.Itoa(int())))
		if errors.Is(, fs.ErrNotExist) {
			return false, nil
		}
		return  == nil, 
	}

	//'/proc' filesystem is not exist, checking of PID existence is done via signalling the process
	//Make sense only if we run in the same process namespace
	 = .Signal(syscall.Signal(0))
	if  == nil {
		return true, nil
	}
	if .Error() == "os: process already finished" {
		return false, nil
	}
	,  := .(syscall.Errno)
	if ! {
		return false, 
	}
	switch  {
	case syscall.ESRCH:
		return false, nil
	case syscall.EPERM:
		return true, nil
	}

	return false, 
}

// SendSignal sends a unix.Signal to the process.
// Currently, SIGSTOP, SIGCONT, SIGTERM and SIGKILL are supported.
func ( *Process) ( syscall.Signal) error {
	return .SendSignalWithContext(context.Background(), )
}

func ( *Process) ( context.Context,  syscall.Signal) error {
	,  := os.FindProcess(int(.Pid))
	if  != nil {
		return 
	}

	 = .Signal()
	if  != nil {
		return 
	}

	return nil
}

// Suspend sends SIGSTOP to the process.
func ( *Process) () error {
	return .SuspendWithContext(context.Background())
}

func ( *Process) ( context.Context) error {
	return .SendSignal(unix.SIGSTOP)
}

// Resume sends SIGCONT to the process.
func ( *Process) () error {
	return .ResumeWithContext(context.Background())
}

func ( *Process) ( context.Context) error {
	return .SendSignal(unix.SIGCONT)
}

// Terminate sends SIGTERM to the process.
func ( *Process) () error {
	return .TerminateWithContext(context.Background())
}

func ( *Process) ( context.Context) error {
	return .SendSignal(unix.SIGTERM)
}

// Kill sends SIGKILL to the process.
func ( *Process) () error {
	return .KillWithContext(context.Background())
}

func ( *Process) ( context.Context) error {
	return .SendSignal(unix.SIGKILL)
}

// Username returns a username of the process.
func ( *Process) () (string, error) {
	return .UsernameWithContext(context.Background())
}

func ( *Process) ( context.Context) (string, error) {
	,  := .Uids()
	if  != nil {
		return "", 
	}
	if len() > 0 {
		,  := user.LookupId(strconv.Itoa(int([0])))
		if  != nil {
			return "", 
		}
		return .Username, nil
	}
	return "", nil
}