// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build unix || (js && wasm) || wasip1 || windows

package os

import (
	
	
	
	
)

// The only signal values guaranteed to be present in the os package on all
// systems are os.Interrupt (send the process an interrupt) and os.Kill (force
// the process to exit). On Windows, sending os.Interrupt to a process with
// os.Process.Signal is not implemented; it will return an error instead of
// sending a signal.
var (
	Interrupt Signal = syscall.SIGINT
	Kill      Signal = syscall.SIGKILL
)

func startProcess( string,  []string,  *ProcAttr) ( *Process,  error) {
	// If there is no SysProcAttr (ie. no Chroot or changed
	// UID/GID), double-check existence of the directory we want
	// to chdir into. We can make the error clearer this way.
	if  != nil && .Sys == nil && .Dir != "" {
		if ,  := Stat(.Dir);  != nil {
			 := .(*PathError)
			.Op = "chdir"
			return nil, 
		}
	}

	 := &syscall.ProcAttr{
		Dir: .Dir,
		Env: .Env,
		Sys: ensurePidfd(.Sys),
	}
	if .Env == nil {
		.Env,  = execenv.Default(.Sys)
		if  != nil {
			return nil, 
		}
	}
	.Files = make([]uintptr, 0, len(.Files))
	for ,  := range .Files {
		.Files = append(.Files, .Fd())
	}

	, ,  := syscall.StartProcess(, , )

	// Make sure we don't run the finalizers of attr.Files.
	runtime.KeepAlive()

	if  != nil {
		return nil, &PathError{Op: "fork/exec", Path: , Err: }
	}

	// For Windows, syscall.StartProcess above already returned a process handle.
	if runtime.GOOS != "windows" {
		var  bool
		,  = getPidfd(.Sys)
		if ! {
			return newPIDProcess(), nil
		}
	}

	return newHandleProcess(, ), nil
}

func ( *Process) () error {
	return .Signal(Kill)
}

// ProcessState stores information about a process, as reported by Wait.
type ProcessState struct {
	pid    int                // The process's id.
	status syscall.WaitStatus // System-dependent status info.
	rusage *syscall.Rusage
}

// Pid returns the process id of the exited process.
func ( *ProcessState) () int {
	return .pid
}

func ( *ProcessState) () bool {
	return .status.Exited()
}

func ( *ProcessState) () bool {
	return .status.ExitStatus() == 0
}

func ( *ProcessState) () any {
	return .status
}

func ( *ProcessState) () any {
	return .rusage
}

func ( *ProcessState) () string {
	if  == nil {
		return "<nil>"
	}
	 := .Sys().(syscall.WaitStatus)
	 := ""
	switch {
	case .Exited():
		 := .ExitStatus()
		if runtime.GOOS == "windows" && uint() >= 1<<16 { // windows uses large hex numbers
			 = "exit status " + itoa.Uitox(uint())
		} else { // unix systems use small decimal integers
			 = "exit status " + itoa.Itoa() // unix
		}
	case .Signaled():
		 = "signal: " + .Signal().String()
	case .Stopped():
		 = "stop signal: " + .StopSignal().String()
		if .StopSignal() == syscall.SIGTRAP && .TrapCause() != 0 {
			 += " (trap " + itoa.Itoa(.TrapCause()) + ")"
		}
	case .Continued():
		 = "continued"
	}
	if .CoreDump() {
		 += " (core dumped)"
	}
	return 
}

// ExitCode returns the exit code of the exited process, or -1
// if the process hasn't exited or was terminated by a signal.
func ( *ProcessState) () int {
	// return -1 if the process hasn't started.
	if  == nil {
		return -1
	}
	return .status.ExitStatus()
}