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