github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/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 }