exec_unix_test.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. // Copyright 2015 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. //go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
  5. package syscall_test
  6. import (
  7. "internal/testenv"
  8. "io"
  9. "math/rand"
  10. "os"
  11. "os/exec"
  12. "os/signal"
  13. "runtime"
  14. "syscall"
  15. "testing"
  16. "time"
  17. "unsafe"
  18. )
  19. type command struct {
  20. pipe io.WriteCloser
  21. proc *exec.Cmd
  22. test *testing.T
  23. }
  24. func (c *command) Info() (pid, pgrp int) {
  25. pid = c.proc.Process.Pid
  26. pgrp, err := syscall.Getpgid(pid)
  27. if err != nil {
  28. c.test.Fatal(err)
  29. }
  30. return
  31. }
  32. func (c *command) Start() {
  33. if err := c.proc.Start(); err != nil {
  34. c.test.Fatal(err)
  35. }
  36. }
  37. func (c *command) Stop() {
  38. c.pipe.Close()
  39. if err := c.proc.Wait(); err != nil {
  40. c.test.Fatal(err)
  41. }
  42. }
  43. func create(t *testing.T) *command {
  44. testenv.MustHaveExec(t)
  45. proc := exec.Command("cat")
  46. stdin, err := proc.StdinPipe()
  47. if err != nil {
  48. t.Fatal(err)
  49. }
  50. return &command{stdin, proc, t}
  51. }
  52. func parent() (pid, pgrp int) {
  53. return syscall.Getpid(), syscall.Getpgrp()
  54. }
  55. func TestZeroSysProcAttr(t *testing.T) {
  56. ppid, ppgrp := parent()
  57. cmd := create(t)
  58. cmd.Start()
  59. defer cmd.Stop()
  60. cpid, cpgrp := cmd.Info()
  61. if cpid == ppid {
  62. t.Fatalf("Parent and child have the same process ID")
  63. }
  64. if cpgrp != ppgrp {
  65. t.Fatalf("Child is not in parent's process group")
  66. }
  67. }
  68. func TestSetpgid(t *testing.T) {
  69. ppid, ppgrp := parent()
  70. cmd := create(t)
  71. cmd.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
  72. cmd.Start()
  73. defer cmd.Stop()
  74. cpid, cpgrp := cmd.Info()
  75. if cpid == ppid {
  76. t.Fatalf("Parent and child have the same process ID")
  77. }
  78. if cpgrp == ppgrp {
  79. t.Fatalf("Parent and child are in the same process group")
  80. }
  81. if cpid != cpgrp {
  82. t.Fatalf("Child's process group is not the child's process ID")
  83. }
  84. }
  85. func TestPgid(t *testing.T) {
  86. ppid, ppgrp := parent()
  87. cmd1 := create(t)
  88. cmd1.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
  89. cmd1.Start()
  90. defer cmd1.Stop()
  91. cpid1, cpgrp1 := cmd1.Info()
  92. if cpid1 == ppid {
  93. t.Fatalf("Parent and child 1 have the same process ID")
  94. }
  95. if cpgrp1 == ppgrp {
  96. t.Fatalf("Parent and child 1 are in the same process group")
  97. }
  98. if cpid1 != cpgrp1 {
  99. t.Fatalf("Child 1's process group is not its process ID")
  100. }
  101. cmd2 := create(t)
  102. cmd2.proc.SysProcAttr = &syscall.SysProcAttr{
  103. Setpgid: true,
  104. Pgid: cpgrp1,
  105. }
  106. cmd2.Start()
  107. defer cmd2.Stop()
  108. cpid2, cpgrp2 := cmd2.Info()
  109. if cpid2 == ppid {
  110. t.Fatalf("Parent and child 2 have the same process ID")
  111. }
  112. if cpgrp2 == ppgrp {
  113. t.Fatalf("Parent and child 2 are in the same process group")
  114. }
  115. if cpid2 == cpgrp2 {
  116. t.Fatalf("Child 2's process group is its process ID")
  117. }
  118. if cpid1 == cpid2 {
  119. t.Fatalf("Child 1 and 2 have the same process ID")
  120. }
  121. if cpgrp1 != cpgrp2 {
  122. t.Fatalf("Child 1 and 2 are not in the same process group")
  123. }
  124. }
  125. func TestForeground(t *testing.T) {
  126. if runtime.GOOS == "hurd" {
  127. t.Skip("skipping; TestForeground: fails on GNU/Hurd")
  128. }
  129. signal.Ignore(syscall.SIGTTIN, syscall.SIGTTOU)
  130. defer signal.Reset()
  131. tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
  132. if err != nil {
  133. t.Skipf("Can't test Foreground. Couldn't open /dev/tty: %s", err)
  134. }
  135. defer tty.Close()
  136. fpgrp := syscall.Pid_t(0)
  137. errno := syscall.Ioctl(tty.Fd(), syscall.TIOCGPGRP, unsafe.Pointer(&fpgrp))
  138. if errno != 0 {
  139. t.Fatalf("TIOCGPGRP failed with error code: %s", errno)
  140. }
  141. if fpgrp == 0 {
  142. t.Fatalf("Foreground process group is zero")
  143. }
  144. ppid, ppgrp := parent()
  145. cmd := create(t)
  146. cmd.proc.SysProcAttr = &syscall.SysProcAttr{
  147. Ctty: int(tty.Fd()),
  148. Foreground: true,
  149. }
  150. cmd.Start()
  151. cpid, cpgrp := cmd.Info()
  152. if cpid == ppid {
  153. t.Fatalf("Parent and child have the same process ID")
  154. }
  155. if cpgrp == ppgrp {
  156. t.Fatalf("Parent and child are in the same process group")
  157. }
  158. if cpid != cpgrp {
  159. t.Fatalf("Child's process group is not the child's process ID")
  160. }
  161. cmd.Stop()
  162. // This call fails on darwin/arm64. The failure doesn't matter, though.
  163. // This is just best effort.
  164. syscall.Ioctl(tty.Fd(), syscall.TIOCSPGRP, unsafe.Pointer(&fpgrp))
  165. }
  166. func TestForegroundSignal(t *testing.T) {
  167. tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
  168. if err != nil {
  169. t.Skipf("couldn't open /dev/tty: %s", err)
  170. }
  171. defer tty.Close()
  172. // This should really be pid_t, however _C_int (aka int32) is generally
  173. // equivalent.
  174. fpgrp := int32(0)
  175. errno := syscall.Ioctl(tty.Fd(), syscall.TIOCGPGRP, unsafe.Pointer(&fpgrp))
  176. if errno != 0 {
  177. t.Fatalf("TIOCGPGRP failed with error code: %s", errno)
  178. }
  179. if fpgrp == 0 {
  180. t.Fatalf("Foreground process group is zero")
  181. }
  182. defer func() {
  183. signal.Ignore(syscall.SIGTTIN, syscall.SIGTTOU)
  184. syscall.Ioctl(tty.Fd(), syscall.TIOCSPGRP, unsafe.Pointer(&fpgrp))
  185. signal.Reset()
  186. }()
  187. ch1 := make(chan os.Signal, 1)
  188. ch2 := make(chan bool)
  189. signal.Notify(ch1, syscall.SIGTTIN, syscall.SIGTTOU)
  190. defer signal.Stop(ch1)
  191. cmd := create(t)
  192. go func() {
  193. cmd.proc.SysProcAttr = &syscall.SysProcAttr{
  194. Ctty: int(tty.Fd()),
  195. Foreground: true,
  196. }
  197. cmd.Start()
  198. cmd.Stop()
  199. close(ch2)
  200. }()
  201. timer := time.NewTimer(30 * time.Second)
  202. defer timer.Stop()
  203. for {
  204. select {
  205. case sig := <-ch1:
  206. t.Errorf("unexpected signal %v", sig)
  207. case <-ch2:
  208. // Success.
  209. return
  210. case <-timer.C:
  211. t.Fatal("timed out waiting for child process")
  212. }
  213. }
  214. }
  215. // Test a couple of cases that SysProcAttr can't handle. Issue 29458.
  216. func TestInvalidExec(t *testing.T) {
  217. t.Parallel()
  218. t.Run("SetCtty-Foreground", func(t *testing.T) {
  219. t.Parallel()
  220. cmd := create(t)
  221. cmd.proc.SysProcAttr = &syscall.SysProcAttr{
  222. Setctty: true,
  223. Foreground: true,
  224. Ctty: 0,
  225. }
  226. if err := cmd.proc.Start(); err == nil {
  227. t.Error("expected error setting both SetCtty and Foreground")
  228. }
  229. })
  230. t.Run("invalid-Ctty", func(t *testing.T) {
  231. t.Parallel()
  232. cmd := create(t)
  233. cmd.proc.SysProcAttr = &syscall.SysProcAttr{
  234. Setctty: true,
  235. Ctty: 3,
  236. }
  237. if err := cmd.proc.Start(); err == nil {
  238. t.Error("expected error with invalid Ctty value")
  239. }
  240. })
  241. }
  242. // TestExec is for issue #41702.
  243. func TestExec(t *testing.T) {
  244. testenv.MustHaveExec(t)
  245. cmd := exec.Command(os.Args[0], "-test.run=TestExecHelper")
  246. cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=2")
  247. o, err := cmd.CombinedOutput()
  248. if err != nil {
  249. t.Errorf("%s\n%v", o, err)
  250. }
  251. }
  252. // TestExecHelper is used by TestExec. It does nothing by itself.
  253. // In testing on macOS 10.14, this used to fail with
  254. // "signal: illegal instruction" more than half the time.
  255. func TestExecHelper(t *testing.T) {
  256. if os.Getenv("GO_WANT_HELPER_PROCESS") != "2" {
  257. return
  258. }
  259. // We don't have to worry about restoring these values.
  260. // We are in a child process that only runs this test,
  261. // and we are going to call syscall.Exec anyhow.
  262. os.Setenv("GO_WANT_HELPER_PROCESS", "3")
  263. stop := time.Now().Add(time.Second)
  264. for i := 0; i < 100; i++ {
  265. go func(i int) {
  266. r := rand.New(rand.NewSource(int64(i)))
  267. for time.Now().Before(stop) {
  268. r.Uint64()
  269. }
  270. }(i)
  271. }
  272. time.Sleep(10 * time.Millisecond)
  273. argv := []string{os.Args[0], "-test.run=TestExecHelper"}
  274. syscall.Exec(os.Args[0], argv, os.Environ())
  275. t.Error("syscall.Exec returned")
  276. }