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  }