blob: eac98fe764313602d859030d8197aa6168b9a251 [file] [log] [blame]
Tobias Klauser88eb85a2018-05-22 14:53:54 +02001// Copyright 2018 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
5package unix_test
6
Stan Hu2334cc12020-09-13 11:36:12 -07007import (
8 "bytes"
9 "io/ioutil"
Brad Fitzpatrickf9927402021-02-15 20:18:12 -080010 "net"
Stan Hu2334cc12020-09-13 11:36:12 -070011 "os"
12 "path"
13 "testing"
14
15 "golang.org/x/sys/unix"
16)
17
18var testData = []byte("This is a test\n")
19
Tobias Klauser88eb85a2018-05-22 14:53:54 +020020// stringsFromByteSlice converts a sequence of attributes to a []string.
21// On Darwin, each entry is a NULL-terminated string.
22func stringsFromByteSlice(buf []byte) []string {
23 var result []string
24 off := 0
25 for i, b := range buf {
26 if b == 0 {
27 result = append(result, string(buf[off:i]))
28 off = i + 1
29 }
30 }
31 return result
32}
Stan Hu2334cc12020-09-13 11:36:12 -070033
34func createTestFile(t *testing.T, dir string) (f *os.File, cleanup func() error) {
Tobias Klauseraf09f732020-09-18 12:13:43 +020035 file, err := ioutil.TempFile(dir, t.Name())
Stan Hu2334cc12020-09-13 11:36:12 -070036 if err != nil {
37 t.Fatal(err)
38 }
39
40 _, err = file.Write(testData)
41 if err != nil {
42 t.Fatal(err)
43 }
44
45 err = file.Close()
46 if err != nil {
47 t.Fatal(err)
48 }
49
50 return file, func() error {
51 return os.Remove(file.Name())
52 }
53}
54
55func TestClonefile(t *testing.T) {
56 file, cleanup := createTestFile(t, "")
57 defer cleanup()
58
59 clonedName := file.Name() + "-cloned"
60 err := unix.Clonefile(file.Name(), clonedName, 0)
Tobias Klauserefd3b9a2020-09-16 11:36:22 +020061 if err == unix.ENOSYS || err == unix.ENOTSUP {
62 t.Skip("clonefile is not available or supported, skipping test")
63 } else if err != nil {
Stan Hu2334cc12020-09-13 11:36:12 -070064 t.Fatal(err)
65 }
66 defer os.Remove(clonedName)
67
68 clonedData, err := ioutil.ReadFile(clonedName)
69 if err != nil {
70 t.Fatal(err)
71 }
72
73 if !bytes.Equal(testData, clonedData) {
74 t.Errorf("Clonefile: got %q, expected %q", clonedData, testData)
75 }
76}
77
78func TestClonefileatWithCwd(t *testing.T) {
79 file, cleanup := createTestFile(t, "")
80 defer cleanup()
81
82 clonedName := file.Name() + "-cloned"
83 err := unix.Clonefileat(unix.AT_FDCWD, file.Name(), unix.AT_FDCWD, clonedName, 0)
Tobias Klauserefd3b9a2020-09-16 11:36:22 +020084 if err == unix.ENOSYS || err == unix.ENOTSUP {
85 t.Skip("clonefileat is not available or supported, skipping test")
86 } else if err != nil {
Stan Hu2334cc12020-09-13 11:36:12 -070087 t.Fatal(err)
88 }
Stan Hu2334cc12020-09-13 11:36:12 -070089 defer os.Remove(clonedName)
90
91 clonedData, err := ioutil.ReadFile(clonedName)
92 if err != nil {
93 t.Fatal(err)
94 }
95
96 if !bytes.Equal(testData, clonedData) {
97 t.Errorf("Clonefileat: got %q, expected %q", clonedData, testData)
98 }
99}
100
101func TestClonefileatWithRelativePaths(t *testing.T) {
102 srcDir, err := ioutil.TempDir("", "src")
103 if err != nil {
104 t.Fatal(err)
105 }
106 defer os.RemoveAll(srcDir)
107
108 dstDir, err := ioutil.TempDir("", "dest")
109 if err != nil {
110 t.Fatal(err)
111 }
112 defer os.RemoveAll(dstDir)
113
114 srcFd, err := unix.Open(srcDir, unix.O_RDONLY|unix.O_DIRECTORY, 0)
115 if err != nil {
116 t.Fatal(err)
117 }
118 defer unix.Close(srcFd)
119
120 dstFd, err := unix.Open(dstDir, unix.O_RDONLY|unix.O_DIRECTORY, 0)
121 if err != nil {
122 t.Fatal(err)
123 }
124 defer unix.Close(dstFd)
125
126 srcFile, cleanup := createTestFile(t, srcDir)
127 defer cleanup()
128
129 dstFile, err := ioutil.TempFile(dstDir, "TestClonefileat")
130 if err != nil {
131 t.Fatal(err)
132 }
133 err = os.Remove(dstFile.Name())
134 if err != nil {
135 t.Fatal(err)
136 }
137
138 src := path.Base(srcFile.Name())
139 dst := path.Base(dstFile.Name())
140 err = unix.Clonefileat(srcFd, src, dstFd, dst, 0)
Tobias Klauserefd3b9a2020-09-16 11:36:22 +0200141 if err == unix.ENOSYS || err == unix.ENOTSUP {
142 t.Skip("clonefileat is not available or supported, skipping test")
143 } else if err != nil {
Stan Hu2334cc12020-09-13 11:36:12 -0700144 t.Fatal(err)
145 }
146
147 clonedData, err := ioutil.ReadFile(dstFile.Name())
148 if err != nil {
149 t.Fatal(err)
150 }
151
152 if !bytes.Equal(testData, clonedData) {
153 t.Errorf("Clonefileat: got %q, expected %q", clonedData, testData)
154 }
155}
156
157func TestFclonefileat(t *testing.T) {
158 file, cleanup := createTestFile(t, "")
159 defer cleanup()
160
161 fd, err := unix.Open(file.Name(), unix.O_RDONLY, 0)
162 if err != nil {
163 t.Fatal(err)
164 }
165 defer unix.Close(fd)
166
167 dstFile, err := ioutil.TempFile("", "TestFclonefileat")
168 if err != nil {
169 t.Fatal(err)
170 }
171 os.Remove(dstFile.Name())
172
173 err = unix.Fclonefileat(fd, unix.AT_FDCWD, dstFile.Name(), 0)
Tobias Klauserefd3b9a2020-09-16 11:36:22 +0200174 if err == unix.ENOSYS || err == unix.ENOTSUP {
175 t.Skip("clonefileat is not available or supported, skipping test")
176 } else if err != nil {
Stan Hu2334cc12020-09-13 11:36:12 -0700177 t.Fatal(err)
178 }
179
180 clonedData, err := ioutil.ReadFile(dstFile.Name())
181 if err != nil {
182 t.Fatal(err)
183 }
184
185 if !bytes.Equal(testData, clonedData) {
186 t.Errorf("Fclonefileat: got %q, expected %q", clonedData, testData)
187 }
188}
Tobias Klauseraf09f732020-09-18 12:13:43 +0200189
190func TestFcntlFstore(t *testing.T) {
191 f, err := ioutil.TempFile("", t.Name())
192 if err != nil {
193 t.Fatal(err)
194 }
195 defer os.Remove(f.Name())
196 defer f.Close()
197
198 fstore := &unix.Fstore_t{
199 Flags: unix.F_ALLOCATEALL,
200 Posmode: unix.F_PEOFPOSMODE,
201 Offset: 0,
202 Length: 1 << 10,
203 }
204 err = unix.FcntlFstore(f.Fd(), unix.F_PREALLOCATE, fstore)
205 if err == unix.EOPNOTSUPP {
206 t.Skipf("fcntl with F_PREALLOCATE not supported, skipping test")
207 } else if err != nil {
208 t.Fatalf("FcntlFstore: %v", err)
209 }
210
211 st, err := f.Stat()
212 if err != nil {
213 t.Fatal(err)
214 }
215
216 if st.Size() != 0 {
217 t.Errorf("FcntlFstore: got size = %d, want %d", st.Size(), 0)
218 }
219
220}
Brad Fitzpatrickf9927402021-02-15 20:18:12 -0800221
222func TestGetsockoptXucred(t *testing.T) {
Tobias Klauser8ebf48a2021-02-18 09:58:46 +0100223 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0)
Brad Fitzpatrickf9927402021-02-15 20:18:12 -0800224 if err != nil {
225 t.Fatalf("Socketpair: %v", err)
226 }
Brad Fitzpatrickf9927402021-02-15 20:18:12 -0800227
228 srvFile := os.NewFile(uintptr(fds[0]), "server")
Tobias Klauser66c3f262021-04-14 11:17:47 +0200229 cliFile := os.NewFile(uintptr(fds[1]), "client")
Brad Fitzpatrickf9927402021-02-15 20:18:12 -0800230 defer srvFile.Close()
Tobias Klauser66c3f262021-04-14 11:17:47 +0200231 defer cliFile.Close()
232
Brad Fitzpatrickf9927402021-02-15 20:18:12 -0800233 srv, err := net.FileConn(srvFile)
234 if err != nil {
235 t.Fatalf("FileConn: %v", err)
236 }
237 defer srv.Close()
238
Brad Fitzpatrickf9927402021-02-15 20:18:12 -0800239 cli, err := net.FileConn(cliFile)
240 if err != nil {
241 t.Fatalf("FileConn: %v", err)
242 }
243 defer cli.Close()
244
245 cred, err := unix.GetsockoptXucred(fds[1], unix.SOL_LOCAL, unix.LOCAL_PEERCRED)
246 if err != nil {
247 t.Fatal(err)
248 }
249 t.Logf("got: %+v", cred)
250 if got, want := cred.Uid, os.Getuid(); int(got) != int(want) {
251 t.Errorf("uid = %v; want %v", got, want)
252 }
Tobias Klauser8ebf48a2021-02-18 09:58:46 +0100253 if cred.Ngroups > 0 {
254 if got, want := cred.Groups[0], os.Getgid(); int(got) != int(want) {
255 t.Errorf("gid = %v; want %v", got, want)
256 }
257 }
Brad Fitzpatrickf9927402021-02-15 20:18:12 -0800258}
Tobias Klauser95da2342021-11-01 15:20:19 +0100259
260func TestSysctlKinfoProc(t *testing.T) {
261 pid := unix.Getpid()
262 kp, err := unix.SysctlKinfoProc("kern.proc.pid", pid)
263 if err != nil {
264 t.Fatalf("SysctlKinfoProc: %v", err)
265 }
266 if got, want := int(kp.Proc.P_pid), pid; got != want {
267 t.Errorf("got pid %d, want %d", got, want)
268 }
269}
Tobias Klausera2f17f72021-11-01 15:23:15 +0100270
271func TestSysctlKinfoProcSlice(t *testing.T) {
272 kps, err := unix.SysctlKinfoProcSlice("kern.proc.all")
273 if err != nil {
274 t.Fatalf("SysctlKinfoProc: %v", err)
275 }
276 if len(kps) == 0 {
277 t.Errorf("SysctlKinfoProcSlice: expected at least one process")
278 }
279
280 uid := unix.Getuid()
281 kps, err = unix.SysctlKinfoProcSlice("kern.proc.uid", uid)
282 if err != nil {
283 t.Fatalf("SysctlKinfoProc: %v", err)
284 }
285 if len(kps) == 0 {
286 t.Errorf("SysctlKinfoProcSlice: expected at least one process")
287 }
288
289 for _, kp := range kps {
290 if got, want := int(kp.Eproc.Ucred.Uid), uid; got != want {
291 t.Errorf("process %d: got uid %d, want %d", kp.Proc.P_pid, got, want)
292 }
293 }
294}