exec_posix.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
  5. package os
  6. import (
  7. "syscall"
  8. )
  9. // The only signal values guaranteed to be present on all systems
  10. // are Interrupt (send the process an interrupt) and Kill (force
  11. // the process to exit).
  12. var (
  13. Interrupt Signal = syscall.SIGINT
  14. Kill Signal = syscall.SIGKILL
  15. )
  16. func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
  17. // If there is no SysProcAttr (ie. no Chroot or changed
  18. // UID/GID), double-check existence of the directory we want
  19. // to chdir into. We can make the error clearer this way.
  20. if attr != nil && attr.Sys == nil && attr.Dir != "" {
  21. if _, err := Stat(attr.Dir); err != nil {
  22. pe := err.(*PathError)
  23. pe.Op = "chdir"
  24. return nil, pe
  25. }
  26. }
  27. sysattr := &syscall.ProcAttr{
  28. Dir: attr.Dir,
  29. Env: attr.Env,
  30. Sys: attr.Sys,
  31. }
  32. if sysattr.Env == nil {
  33. sysattr.Env = Environ()
  34. }
  35. for _, f := range attr.Files {
  36. sysattr.Files = append(sysattr.Files, f.Fd())
  37. }
  38. pid, h, e := syscall.StartProcess(name, argv, sysattr)
  39. if e != nil {
  40. return nil, &PathError{"fork/exec", name, e}
  41. }
  42. return newProcess(pid, h), nil
  43. }
  44. func (p *Process) kill() error {
  45. return p.Signal(Kill)
  46. }
  47. // ProcessState stores information about a process, as reported by Wait.
  48. type ProcessState struct {
  49. pid int // The process's id.
  50. status syscall.WaitStatus // System-dependent status info.
  51. rusage *syscall.Rusage
  52. }
  53. // Pid returns the process id of the exited process.
  54. func (p *ProcessState) Pid() int {
  55. return p.pid
  56. }
  57. func (p *ProcessState) exited() bool {
  58. return p.status.Exited()
  59. }
  60. func (p *ProcessState) success() bool {
  61. return p.status.ExitStatus() == 0
  62. }
  63. func (p *ProcessState) sys() interface{} {
  64. return p.status
  65. }
  66. func (p *ProcessState) sysUsage() interface{} {
  67. return p.rusage
  68. }
  69. // Convert i to decimal string.
  70. func itod(i int) string {
  71. if i == 0 {
  72. return "0"
  73. }
  74. u := uint64(i)
  75. if i < 0 {
  76. u = -u
  77. }
  78. // Assemble decimal in reverse order.
  79. var b [32]byte
  80. bp := len(b)
  81. for ; u > 0; u /= 10 {
  82. bp--
  83. b[bp] = byte(u%10) + '0'
  84. }
  85. if i < 0 {
  86. bp--
  87. b[bp] = '-'
  88. }
  89. return string(b[bp:])
  90. }
  91. func (p *ProcessState) String() string {
  92. if p == nil {
  93. return "<nil>"
  94. }
  95. status := p.Sys().(syscall.WaitStatus)
  96. res := ""
  97. switch {
  98. case status.Exited():
  99. res = "exit status " + itod(status.ExitStatus())
  100. case status.Signaled():
  101. res = "signal: " + status.Signal().String()
  102. case status.Stopped():
  103. res = "stop signal: " + status.StopSignal().String()
  104. if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 {
  105. res += " (trap " + itod(status.TrapCause()) + ")"
  106. }
  107. case status.Continued():
  108. res = "continued"
  109. }
  110. if status.CoreDump() {
  111. res += " (core dumped)"
  112. }
  113. return res
  114. }