github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/syscall/syscall_linux_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  package syscall_test
     6  
     7  import (
     8  	"bufio"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"os"
    13  	"os/exec"
    14  	"os/signal"
    15  	"path/filepath"
    16  	"syscall"
    17  	"testing"
    18  	"time"
    19  )
    20  
    21  func TestMain(m *testing.M) {
    22  	if os.Getenv("GO_DEATHSIG_PARENT") == "1" {
    23  		deathSignalParent()
    24  	} else if os.Getenv("GO_DEATHSIG_CHILD") == "1" {
    25  		deathSignalChild()
    26  	}
    27  
    28  	os.Exit(m.Run())
    29  }
    30  
    31  func TestLinuxDeathSignal(t *testing.T) {
    32  	if os.Getuid() != 0 {
    33  		t.Skip("skipping root only test")
    34  	}
    35  
    36  	// Copy the test binary to a location that a non-root user can read/execute
    37  	// after we drop privileges
    38  	tempDir, err := ioutil.TempDir("", "TestDeathSignal")
    39  	if err != nil {
    40  		t.Fatalf("cannot create temporary directory: %v", err)
    41  	}
    42  	defer os.RemoveAll(tempDir)
    43  	os.Chmod(tempDir, 0755)
    44  
    45  	tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0]))
    46  
    47  	src, err := os.Open(os.Args[0])
    48  	if err != nil {
    49  		t.Fatalf("cannot open binary %q, %v", os.Args[0], err)
    50  	}
    51  	defer src.Close()
    52  
    53  	dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
    54  	if err != nil {
    55  		t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err)
    56  	}
    57  	if _, err := io.Copy(dst, src); err != nil {
    58  		t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err)
    59  	}
    60  	err = dst.Close()
    61  	if err != nil {
    62  		t.Fatalf("failed to close test binary %q, %v", tmpBinary, err)
    63  	}
    64  
    65  	cmd := exec.Command(tmpBinary)
    66  	cmd.Env = []string{"GO_DEATHSIG_PARENT=1"}
    67  	chldStdin, err := cmd.StdinPipe()
    68  	if err != nil {
    69  		t.Fatalf("failed to create new stdin pipe: %v", err)
    70  	}
    71  	chldStdout, err := cmd.StdoutPipe()
    72  	if err != nil {
    73  		t.Fatalf("failed to create new stdout pipe: %v", err)
    74  	}
    75  	cmd.Stderr = os.Stderr
    76  
    77  	err = cmd.Start()
    78  	defer cmd.Wait()
    79  	if err != nil {
    80  		t.Fatalf("failed to start first child process: %v", err)
    81  	}
    82  
    83  	chldPipe := bufio.NewReader(chldStdout)
    84  
    85  	if got, err := chldPipe.ReadString('\n'); got == "start\n" {
    86  		syscall.Kill(cmd.Process.Pid, syscall.SIGTERM)
    87  
    88  		go func() {
    89  			time.Sleep(5 * time.Second)
    90  			chldStdin.Close()
    91  		}()
    92  
    93  		want := "ok\n"
    94  		if got, err = chldPipe.ReadString('\n'); got != want {
    95  			t.Fatalf("expected %q, received %q, %v", want, got, err)
    96  		}
    97  	} else {
    98  		t.Fatalf("did not receive start from child, received %q, %v", got, err)
    99  	}
   100  }
   101  
   102  func deathSignalParent() {
   103  	cmd := exec.Command(os.Args[0])
   104  	cmd.Env = []string{"GO_DEATHSIG_CHILD=1"}
   105  	cmd.Stdin = os.Stdin
   106  	cmd.Stdout = os.Stdout
   107  	attrs := syscall.SysProcAttr{
   108  		Pdeathsig: syscall.SIGUSR1,
   109  		// UID/GID 99 is the user/group "nobody" on RHEL/Fedora and is
   110  		// unused on Ubuntu
   111  		Credential: &syscall.Credential{Uid: 99, Gid: 99},
   112  	}
   113  	cmd.SysProcAttr = &attrs
   114  
   115  	err := cmd.Start()
   116  	if err != nil {
   117  		fmt.Fprintf(os.Stderr, "death signal parent error: %v\n", err)
   118  		os.Exit(1)
   119  	}
   120  	cmd.Wait()
   121  	os.Exit(0)
   122  }
   123  
   124  func deathSignalChild() {
   125  	c := make(chan os.Signal, 1)
   126  	signal.Notify(c, syscall.SIGUSR1)
   127  	go func() {
   128  		<-c
   129  		fmt.Println("ok")
   130  		os.Exit(0)
   131  	}()
   132  	fmt.Println("start")
   133  
   134  	buf := make([]byte, 32)
   135  	os.Stdin.Read(buf)
   136  
   137  	// We expected to be signaled before stdin closed
   138  	fmt.Println("not ok")
   139  	os.Exit(1)
   140  }
   141  
   142  func TestParseNetlinkMessage(t *testing.T) {
   143  	for i, b := range [][]byte{
   144  		{103, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 5, 8, 0, 3,
   145  			0, 8, 0, 6, 0, 0, 0, 0, 1, 63, 0, 10, 0, 69, 16, 0, 59, 39, 82, 64, 0, 64, 6, 21, 89, 127, 0, 0,
   146  			1, 127, 0, 0, 1, 230, 228, 31, 144, 32, 186, 155, 211, 185, 151, 209, 179, 128, 24, 1, 86,
   147  			53, 119, 0, 0, 1, 1, 8, 10, 0, 17, 234, 12, 0, 17, 189, 126, 107, 106, 108, 107, 106, 13, 10,
   148  		},
   149  		{106, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 3, 8, 0, 3,
   150  			0, 8, 0, 6, 0, 0, 0, 0, 1, 66, 0, 10, 0, 69, 0, 0, 62, 230, 255, 64, 0, 64, 6, 85, 184, 127, 0, 0,
   151  			1, 127, 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 65, 250, 60, 192, 97, 128, 24, 1, 86, 253, 21, 0,
   152  			0, 1, 1, 8, 10, 0, 51, 106, 89, 0, 51, 102, 198, 108, 104, 106, 108, 107, 104, 108, 107, 104, 10,
   153  		},
   154  		{102, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 1, 8, 0, 3, 0,
   155  			8, 0, 6, 0, 0, 0, 0, 1, 62, 0, 10, 0, 69, 0, 0, 58, 231, 2, 64, 0, 64, 6, 85, 185, 127, 0, 0, 1, 127,
   156  			0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 86, 250, 60, 192, 97, 128, 24, 1, 86, 104, 64, 0, 0, 1, 1, 8,
   157  			10, 0, 52, 198, 200, 0, 51, 135, 232, 101, 115, 97, 103, 103, 10,
   158  		},
   159  	} {
   160  		m, err := syscall.ParseNetlinkMessage(b)
   161  		if err != syscall.EINVAL {
   162  			t.Errorf("#%d: got %v; want EINVAL", i, err)
   163  		}
   164  		if m != nil {
   165  			t.Errorf("#%d: got %v; want nil", i, m)
   166  		}
   167  	}
   168  }