...

Source file src/os/exec_posix.go

Documentation: os

		 1  // Copyright 2009 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
		 6  // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
		 7  
		 8  package os
		 9  
		10  import (
		11  	"internal/itoa"
		12  	"internal/syscall/execenv"
		13  	"runtime"
		14  	"syscall"
		15  )
		16  
		17  // The only signal values guaranteed to be present in the os package on all
		18  // systems are os.Interrupt (send the process an interrupt) and os.Kill (force
		19  // the process to exit). On Windows, sending os.Interrupt to a process with
		20  // os.Process.Signal is not implemented; it will return an error instead of
		21  // sending a signal.
		22  var (
		23  	Interrupt Signal = syscall.SIGINT
		24  	Kill			Signal = syscall.SIGKILL
		25  )
		26  
		27  func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
		28  	// If there is no SysProcAttr (ie. no Chroot or changed
		29  	// UID/GID), double-check existence of the directory we want
		30  	// to chdir into. We can make the error clearer this way.
		31  	if attr != nil && attr.Sys == nil && attr.Dir != "" {
		32  		if _, err := Stat(attr.Dir); err != nil {
		33  			pe := err.(*PathError)
		34  			pe.Op = "chdir"
		35  			return nil, pe
		36  		}
		37  	}
		38  
		39  	sysattr := &syscall.ProcAttr{
		40  		Dir: attr.Dir,
		41  		Env: attr.Env,
		42  		Sys: attr.Sys,
		43  	}
		44  	if sysattr.Env == nil {
		45  		sysattr.Env, err = execenv.Default(sysattr.Sys)
		46  		if err != nil {
		47  			return nil, err
		48  		}
		49  	}
		50  	sysattr.Files = make([]uintptr, 0, len(attr.Files))
		51  	for _, f := range attr.Files {
		52  		sysattr.Files = append(sysattr.Files, f.Fd())
		53  	}
		54  
		55  	pid, h, e := syscall.StartProcess(name, argv, sysattr)
		56  
		57  	// Make sure we don't run the finalizers of attr.Files.
		58  	runtime.KeepAlive(attr)
		59  
		60  	if e != nil {
		61  		return nil, &PathError{Op: "fork/exec", Path: name, Err: e}
		62  	}
		63  
		64  	return newProcess(pid, h), nil
		65  }
		66  
		67  func (p *Process) kill() error {
		68  	return p.Signal(Kill)
		69  }
		70  
		71  // ProcessState stores information about a process, as reported by Wait.
		72  type ProcessState struct {
		73  	pid		int								// The process's id.
		74  	status syscall.WaitStatus // System-dependent status info.
		75  	rusage *syscall.Rusage
		76  }
		77  
		78  // Pid returns the process id of the exited process.
		79  func (p *ProcessState) Pid() int {
		80  	return p.pid
		81  }
		82  
		83  func (p *ProcessState) exited() bool {
		84  	return p.status.Exited()
		85  }
		86  
		87  func (p *ProcessState) success() bool {
		88  	return p.status.ExitStatus() == 0
		89  }
		90  
		91  func (p *ProcessState) sys() interface{} {
		92  	return p.status
		93  }
		94  
		95  func (p *ProcessState) sysUsage() interface{} {
		96  	return p.rusage
		97  }
		98  
		99  func (p *ProcessState) String() string {
	 100  	if p == nil {
	 101  		return "<nil>"
	 102  	}
	 103  	status := p.Sys().(syscall.WaitStatus)
	 104  	res := ""
	 105  	switch {
	 106  	case status.Exited():
	 107  		code := status.ExitStatus()
	 108  		if runtime.GOOS == "windows" && uint(code) >= 1<<16 { // windows uses large hex numbers
	 109  			res = "exit status " + uitox(uint(code))
	 110  		} else { // unix systems use small decimal integers
	 111  			res = "exit status " + itoa.Itoa(code) // unix
	 112  		}
	 113  	case status.Signaled():
	 114  		res = "signal: " + status.Signal().String()
	 115  	case status.Stopped():
	 116  		res = "stop signal: " + status.StopSignal().String()
	 117  		if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 {
	 118  			res += " (trap " + itoa.Itoa(status.TrapCause()) + ")"
	 119  		}
	 120  	case status.Continued():
	 121  		res = "continued"
	 122  	}
	 123  	if status.CoreDump() {
	 124  		res += " (core dumped)"
	 125  	}
	 126  	return res
	 127  }
	 128  
	 129  // ExitCode returns the exit code of the exited process, or -1
	 130  // if the process hasn't exited or was terminated by a signal.
	 131  func (p *ProcessState) ExitCode() int {
	 132  	// return -1 if the process hasn't started.
	 133  	if p == nil {
	 134  		return -1
	 135  	}
	 136  	return p.status.ExitStatus()
	 137  }
	 138  

View as plain text