Home | History | Annotate | Download | only in syscall
      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 	"internal/testenv"
     11 	"io"
     12 	"os"
     13 	"os/exec"
     14 	"os/signal"
     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 	testenv.MustHaveExec(t)
     52 
     53 	proc := exec.Command("cat")
     54 	stdin, err := proc.StdinPipe()
     55 	if err != nil {
     56 		t.Fatal(err)
     57 	}
     58 
     59 	return &command{stdin, proc, t}
     60 }
     61 
     62 func parent() (pid, pgrp int) {
     63 	return syscall.Getpid(), syscall.Getpgrp()
     64 }
     65 
     66 func TestZeroSysProcAttr(t *testing.T) {
     67 	ppid, ppgrp := parent()
     68 
     69 	cmd := create(t)
     70 
     71 	cmd.Start()
     72 	defer cmd.Stop()
     73 
     74 	cpid, cpgrp := cmd.Info()
     75 
     76 	if cpid == ppid {
     77 		t.Fatalf("Parent and child have the same process ID")
     78 	}
     79 
     80 	if cpgrp != ppgrp {
     81 		t.Fatalf("Child is not in parent's process group")
     82 	}
     83 }
     84 
     85 func TestSetpgid(t *testing.T) {
     86 	ppid, ppgrp := parent()
     87 
     88 	cmd := create(t)
     89 
     90 	cmd.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
     91 	cmd.Start()
     92 	defer cmd.Stop()
     93 
     94 	cpid, cpgrp := cmd.Info()
     95 
     96 	if cpid == ppid {
     97 		t.Fatalf("Parent and child have the same process ID")
     98 	}
     99 
    100 	if cpgrp == ppgrp {
    101 		t.Fatalf("Parent and child are in the same process group")
    102 	}
    103 
    104 	if cpid != cpgrp {
    105 		t.Fatalf("Child's process group is not the child's process ID")
    106 	}
    107 }
    108 
    109 func TestPgid(t *testing.T) {
    110 	ppid, ppgrp := parent()
    111 
    112 	cmd1 := create(t)
    113 
    114 	cmd1.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
    115 	cmd1.Start()
    116 	defer cmd1.Stop()
    117 
    118 	cpid1, cpgrp1 := cmd1.Info()
    119 
    120 	if cpid1 == ppid {
    121 		t.Fatalf("Parent and child 1 have the same process ID")
    122 	}
    123 
    124 	if cpgrp1 == ppgrp {
    125 		t.Fatalf("Parent and child 1 are in the same process group")
    126 	}
    127 
    128 	if cpid1 != cpgrp1 {
    129 		t.Fatalf("Child 1's process group is not its process ID")
    130 	}
    131 
    132 	cmd2 := create(t)
    133 
    134 	cmd2.proc.SysProcAttr = &syscall.SysProcAttr{
    135 		Setpgid: true,
    136 		Pgid:    cpgrp1,
    137 	}
    138 	cmd2.Start()
    139 	defer cmd2.Stop()
    140 
    141 	cpid2, cpgrp2 := cmd2.Info()
    142 
    143 	if cpid2 == ppid {
    144 		t.Fatalf("Parent and child 2 have the same process ID")
    145 	}
    146 
    147 	if cpgrp2 == ppgrp {
    148 		t.Fatalf("Parent and child 2 are in the same process group")
    149 	}
    150 
    151 	if cpid2 == cpgrp2 {
    152 		t.Fatalf("Child 2's process group is its process ID")
    153 	}
    154 
    155 	if cpid1 == cpid2 {
    156 		t.Fatalf("Child 1 and 2 have the same process ID")
    157 	}
    158 
    159 	if cpgrp1 != cpgrp2 {
    160 		t.Fatalf("Child 1 and 2 are not in the same process group")
    161 	}
    162 }
    163 
    164 func TestForeground(t *testing.T) {
    165 	signal.Ignore(syscall.SIGTTIN, syscall.SIGTTOU)
    166 
    167 	tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
    168 	if err != nil {
    169 		t.Skipf("Can't test Foreground. Couldn't open /dev/tty: %s", err)
    170 	}
    171 
    172 	fpgrp := 0
    173 
    174 	errno := syscall.Ioctl(tty.Fd(), syscall.TIOCGPGRP, uintptr(unsafe.Pointer(&fpgrp)))
    175 	if errno != 0 {
    176 		t.Fatalf("TIOCGPGRP failed with error code: %s", errno)
    177 	}
    178 
    179 	if fpgrp == 0 {
    180 		t.Fatalf("Foreground process group is zero")
    181 	}
    182 
    183 	ppid, ppgrp := parent()
    184 
    185 	cmd := create(t)
    186 
    187 	cmd.proc.SysProcAttr = &syscall.SysProcAttr{
    188 		Ctty:       int(tty.Fd()),
    189 		Foreground: true,
    190 	}
    191 	cmd.Start()
    192 
    193 	cpid, cpgrp := cmd.Info()
    194 
    195 	if cpid == ppid {
    196 		t.Fatalf("Parent and child have the same process ID")
    197 	}
    198 
    199 	if cpgrp == ppgrp {
    200 		t.Fatalf("Parent and child are in the same process group")
    201 	}
    202 
    203 	if cpid != cpgrp {
    204 		t.Fatalf("Child's process group is not the child's process ID")
    205 	}
    206 
    207 	cmd.Stop()
    208 
    209 	errno = syscall.Ioctl(tty.Fd(), syscall.TIOCSPGRP, uintptr(unsafe.Pointer(&fpgrp)))
    210 	if errno != 0 {
    211 		t.Fatalf("TIOCSPGRP failed with error code: %s", errno)
    212 	}
    213 
    214 	signal.Reset()
    215 }
    216