rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/syscall/exec_unix_test.go (about) 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 5 // +build darwin dragonfly freebsd linux netbsd openbsd solaris 6 7 package syscall_test 8 9 import ( 10 "io" 11 "os" 12 "os/exec" 13 "os/signal" 14 "runtime" 15 "syscall" 16 "testing" 17 "unsafe" 18 ) 19 20 type command struct { 21 pipe io.WriteCloser 22 proc *exec.Cmd 23 test *testing.T 24 } 25 26 func (c *command) Info() (pid, pgrp int) { 27 pid = c.proc.Process.Pid 28 29 pgrp, err := syscall.Getpgid(pid) 30 if err != nil { 31 c.test.Fatal(err) 32 } 33 34 return 35 } 36 37 func (c *command) Start() { 38 if err := c.proc.Start(); err != nil { 39 c.test.Fatal(err) 40 } 41 } 42 43 func (c *command) Stop() { 44 c.pipe.Close() 45 if err := c.proc.Wait(); err != nil { 46 c.test.Fatal(err) 47 } 48 } 49 50 func create(t *testing.T) *command { 51 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { 52 t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH) 53 } 54 proc := exec.Command("cat") 55 stdin, err := proc.StdinPipe() 56 if err != nil { 57 t.Fatal(err) 58 } 59 60 return &command{stdin, proc, t} 61 } 62 63 func parent() (pid, pgrp int) { 64 return syscall.Getpid(), syscall.Getpgrp() 65 } 66 67 func TestZeroSysProcAttr(t *testing.T) { 68 ppid, ppgrp := parent() 69 70 cmd := create(t) 71 72 cmd.Start() 73 defer cmd.Stop() 74 75 cpid, cpgrp := cmd.Info() 76 77 if cpid == ppid { 78 t.Fatalf("Parent and child have the same process ID") 79 } 80 81 if cpgrp != ppgrp { 82 t.Fatalf("Child is not in parent's process group") 83 } 84 } 85 86 func TestSetpgid(t *testing.T) { 87 ppid, ppgrp := parent() 88 89 cmd := create(t) 90 91 cmd.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} 92 cmd.Start() 93 defer cmd.Stop() 94 95 cpid, cpgrp := cmd.Info() 96 97 if cpid == ppid { 98 t.Fatalf("Parent and child have the same process ID") 99 } 100 101 if cpgrp == ppgrp { 102 t.Fatalf("Parent and child are in the same process group") 103 } 104 105 if cpid != cpgrp { 106 t.Fatalf("Child's process group is not the child's process ID") 107 } 108 } 109 110 func TestPgid(t *testing.T) { 111 ppid, ppgrp := parent() 112 113 cmd1 := create(t) 114 115 cmd1.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} 116 cmd1.Start() 117 defer cmd1.Stop() 118 119 cpid1, cpgrp1 := cmd1.Info() 120 121 if cpid1 == ppid { 122 t.Fatalf("Parent and child 1 have the same process ID") 123 } 124 125 if cpgrp1 == ppgrp { 126 t.Fatalf("Parent and child 1 are in the same process group") 127 } 128 129 if cpid1 != cpgrp1 { 130 t.Fatalf("Child 1's process group is not its process ID") 131 } 132 133 cmd2 := create(t) 134 135 cmd2.proc.SysProcAttr = &syscall.SysProcAttr{ 136 Setpgid: true, 137 Pgid: cpgrp1, 138 } 139 cmd2.Start() 140 defer cmd2.Stop() 141 142 cpid2, cpgrp2 := cmd2.Info() 143 144 if cpid2 == ppid { 145 t.Fatalf("Parent and child 2 have the same process ID") 146 } 147 148 if cpgrp2 == ppgrp { 149 t.Fatalf("Parent and child 2 are in the same process group") 150 } 151 152 if cpid2 == cpgrp2 { 153 t.Fatalf("Child 2's process group is its process ID") 154 } 155 156 if cpid1 == cpid2 { 157 t.Fatalf("Child 1 and 2 have the same process ID") 158 } 159 160 if cpgrp1 != cpgrp2 { 161 t.Fatalf("Child 1 and 2 are not in the same process group") 162 } 163 } 164 165 func TestForeground(t *testing.T) { 166 signal.Ignore(syscall.SIGTTIN, syscall.SIGTTOU) 167 168 tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) 169 if err != nil { 170 t.Skipf("Can't test Foreground. Couldn't open /dev/tty: %s", err) 171 } 172 173 fpgrp := 0 174 175 errno := syscall.Ioctl(tty.Fd(), syscall.TIOCGPGRP, uintptr(unsafe.Pointer(&fpgrp))) 176 if errno != 0 { 177 t.Fatalf("TIOCGPGRP failed with error code: %s", errno) 178 } 179 180 if fpgrp == 0 { 181 t.Fatalf("Foreground process group is zero") 182 } 183 184 ppid, ppgrp := parent() 185 186 cmd := create(t) 187 188 cmd.proc.SysProcAttr = &syscall.SysProcAttr{ 189 Ctty: int(tty.Fd()), 190 Foreground: true, 191 } 192 cmd.Start() 193 194 cpid, cpgrp := cmd.Info() 195 196 if cpid == ppid { 197 t.Fatalf("Parent and child have the same process ID") 198 } 199 200 if cpgrp == ppgrp { 201 t.Fatalf("Parent and child are in the same process group") 202 } 203 204 if cpid != cpgrp { 205 t.Fatalf("Child's process group is not the child's process ID") 206 } 207 208 cmd.Stop() 209 210 errno = syscall.Ioctl(tty.Fd(), syscall.TIOCSPGRP, uintptr(unsafe.Pointer(&fpgrp))) 211 if errno != 0 { 212 t.Fatalf("TIOCSPGRP failed with error code: %s", errno) 213 } 214 215 signal.Reset() 216 }