Source file
src/runtime/signal_linux_test.go
1
2
3
4
5 package runtime_test
6
7 import (
8 "bufio"
9 "bytes"
10 "errors"
11 "internal/testenv"
12 "io"
13 "os"
14 "os/exec"
15 "strings"
16 "syscall"
17 "testing"
18 )
19
20
21
22
23
24 func TestSignalPid1(t *testing.T) {
25 t.Parallel()
26
27 exe, err := buildTestProg(t, "testprog")
28 if err != nil {
29 t.Fatal(err)
30 }
31
32 cmd := testenv.Command(t, exe, "SignalPid1")
33 cmd.SysProcAttr = &syscall.SysProcAttr{
34 Cloneflags: syscall.CLONE_NEWPID | syscall.CLONE_NEWUSER,
35 UidMappings: []syscall.SysProcIDMap{
36 {ContainerID: 0, HostID: os.Getuid(), Size: 1},
37 },
38 GidMappings: []syscall.SysProcIDMap{
39 {ContainerID: 0, HostID: os.Getgid(), Size: 1},
40 },
41 }
42 stdout, err := cmd.StdoutPipe()
43 if err != nil {
44 t.Fatal(err)
45 }
46 var stderr bytes.Buffer
47 cmd.Stderr = &stderr
48 if err := cmd.Start(); err != nil {
49 t.Skipf("cannot create PID namespace (may require unprivileged user namespaces): %v", err)
50 }
51
52 waited := false
53 defer func() {
54 if !waited {
55 cmd.Process.Kill()
56 cmd.Wait()
57 }
58 }()
59
60
61 r := bufio.NewReader(stdout)
62 line, err := r.ReadString('\n')
63 if err != nil {
64 t.Fatalf("reading from child: %v", err)
65 }
66 if strings.TrimRight(line, "\n") != "ready" {
67 t.Fatalf("unexpected output from child: %q", line)
68 }
69 go io.Copy(io.Discard, r)
70
71 const (
72 signal = syscall.SIGTERM
73 expExitCode = int(128 + signal)
74 )
75
76 if err := cmd.Process.Signal(signal); err != nil {
77 t.Fatalf("sending signal %d (%q): %v", signal, signal, err)
78 }
79
80 err = cmd.Wait()
81 waited = true
82 t.Logf("child: %v", err)
83 if s := stderr.String(); s != "" {
84 t.Fatalf("child stderr: %s", s)
85 }
86 if exitErr, ok := errors.AsType[*exec.ExitError](err); ok {
87 if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
88 if ec := status.ExitStatus(); ec == expExitCode {
89 return
90 }
91 }
92 }
93
94 t.Errorf("Want child exited with %d, got: %+v", expExitCode, err)
95 }
96
View as plain text