1
2
3
4
5 package unix_test
6
7 import (
8 "bytes"
9 "net"
10 "os"
11 "path/filepath"
12 "testing"
13
14 "golang.org/x/sys/unix"
15 )
16
17 var testData = []byte("This is a test\n")
18
19
20
21 func stringsFromByteSlice(buf []byte) []string {
22 var result []string
23 off := 0
24 for i, b := range buf {
25 if b == 0 {
26 result = append(result, string(buf[off:i]))
27 off = i + 1
28 }
29 }
30 return result
31 }
32
33 func createTestFile(t *testing.T) string {
34 filename := filepath.Join(t.TempDir(), t.Name())
35 err := os.WriteFile(filename, testData, 0600)
36 if err != nil {
37 t.Fatal(err)
38 }
39 return filename
40 }
41
42 func TestClonefile(t *testing.T) {
43 fileName := createTestFile(t)
44
45 clonedName := fileName + "-cloned"
46 err := unix.Clonefile(fileName, clonedName, 0)
47 if err == unix.ENOSYS || err == unix.ENOTSUP {
48 t.Skip("clonefile is not available or supported, skipping test")
49 } else if err != nil {
50 t.Fatal(err)
51 }
52
53 clonedData, err := os.ReadFile(clonedName)
54 if err != nil {
55 t.Fatal(err)
56 }
57
58 if !bytes.Equal(testData, clonedData) {
59 t.Errorf("Clonefile: got %q, expected %q", clonedData, testData)
60 }
61 }
62
63 func TestClonefileatWithCwd(t *testing.T) {
64 fileName := createTestFile(t)
65
66 clonedName := fileName + "-cloned"
67 err := unix.Clonefileat(unix.AT_FDCWD, fileName, unix.AT_FDCWD, clonedName, 0)
68 if err == unix.ENOSYS || err == unix.ENOTSUP {
69 t.Skip("clonefileat is not available or supported, skipping test")
70 } else if err != nil {
71 t.Fatal(err)
72 }
73
74 clonedData, err := os.ReadFile(clonedName)
75 if err != nil {
76 t.Fatal(err)
77 }
78
79 if !bytes.Equal(testData, clonedData) {
80 t.Errorf("Clonefileat: got %q, expected %q", clonedData, testData)
81 }
82 }
83
84 func TestClonefileatWithRelativePaths(t *testing.T) {
85 srcFileName := createTestFile(t)
86 srcDir := filepath.Dir(srcFileName)
87 srcFd, err := unix.Open(srcDir, unix.O_RDONLY|unix.O_DIRECTORY, 0)
88 if err != nil {
89 t.Fatal(err)
90 }
91 defer unix.Close(srcFd)
92
93 dstDir := t.TempDir()
94 dstFd, err := unix.Open(dstDir, unix.O_RDONLY|unix.O_DIRECTORY, 0)
95 if err != nil {
96 t.Fatal(err)
97 }
98 defer unix.Close(dstFd)
99
100 dstFile, err := os.Create(filepath.Join(dstDir, "TestClonefileat"))
101 if err != nil {
102 t.Fatal(err)
103 }
104 err = os.Remove(dstFile.Name())
105 if err != nil {
106 t.Fatal(err)
107 }
108
109 src := filepath.Base(srcFileName)
110 dst := filepath.Base(dstFile.Name())
111 err = unix.Clonefileat(srcFd, src, dstFd, dst, 0)
112 if err == unix.ENOSYS || err == unix.ENOTSUP {
113 t.Skip("clonefileat is not available or supported, skipping test")
114 } else if err != nil {
115 t.Fatal(err)
116 }
117
118 clonedData, err := os.ReadFile(dstFile.Name())
119 if err != nil {
120 t.Fatal(err)
121 }
122
123 if !bytes.Equal(testData, clonedData) {
124 t.Errorf("Clonefileat: got %q, expected %q", clonedData, testData)
125 }
126 }
127
128 func TestFclonefileat(t *testing.T) {
129 fileName := createTestFile(t)
130 dir := filepath.Dir(fileName)
131
132 fd, err := unix.Open(fileName, unix.O_RDONLY, 0)
133 if err != nil {
134 t.Fatal(err)
135 }
136 defer unix.Close(fd)
137
138 dstFile, err := os.Create(filepath.Join(dir, "dst"))
139 if err != nil {
140 t.Fatal(err)
141 }
142 os.Remove(dstFile.Name())
143
144 err = unix.Fclonefileat(fd, unix.AT_FDCWD, dstFile.Name(), 0)
145 if err == unix.ENOSYS || err == unix.ENOTSUP {
146 t.Skip("clonefileat is not available or supported, skipping test")
147 } else if err != nil {
148 t.Fatal(err)
149 }
150
151 clonedData, err := os.ReadFile(dstFile.Name())
152 if err != nil {
153 t.Fatal(err)
154 }
155
156 if !bytes.Equal(testData, clonedData) {
157 t.Errorf("Fclonefileat: got %q, expected %q", clonedData, testData)
158 }
159 }
160
161 func TestFcntlFstore(t *testing.T) {
162 f, err := os.CreateTemp(t.TempDir(), t.Name())
163 if err != nil {
164 t.Fatal(err)
165 }
166 defer f.Close()
167
168 fstore := &unix.Fstore_t{
169 Flags: unix.F_ALLOCATEALL,
170 Posmode: unix.F_PEOFPOSMODE,
171 Offset: 0,
172 Length: 1 << 10,
173 }
174 err = unix.FcntlFstore(f.Fd(), unix.F_PREALLOCATE, fstore)
175 if err == unix.EOPNOTSUPP {
176 t.Skipf("fcntl with F_PREALLOCATE not supported, skipping test")
177 } else if err != nil {
178 t.Fatalf("FcntlFstore: %v", err)
179 }
180
181 st, err := f.Stat()
182 if err != nil {
183 t.Fatal(err)
184 }
185
186 if st.Size() != 0 {
187 t.Errorf("FcntlFstore: got size = %d, want %d", st.Size(), 0)
188 }
189
190 }
191
192 func TestGetsockoptXucred(t *testing.T) {
193 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0)
194 if err != nil {
195 t.Fatalf("Socketpair: %v", err)
196 }
197
198 srvFile := os.NewFile(uintptr(fds[0]), "server")
199 cliFile := os.NewFile(uintptr(fds[1]), "client")
200 defer srvFile.Close()
201 defer cliFile.Close()
202
203 srv, err := net.FileConn(srvFile)
204 if err != nil {
205 t.Fatalf("FileConn: %v", err)
206 }
207 defer srv.Close()
208
209 cli, err := net.FileConn(cliFile)
210 if err != nil {
211 t.Fatalf("FileConn: %v", err)
212 }
213 defer cli.Close()
214
215 cred, err := unix.GetsockoptXucred(fds[1], unix.SOL_LOCAL, unix.LOCAL_PEERCRED)
216 if err != nil {
217 t.Fatal(err)
218 }
219 t.Logf("got: %+v", cred)
220 if got, want := cred.Uid, os.Getuid(); int(got) != int(want) {
221 t.Errorf("uid = %v; want %v", got, want)
222 }
223 if cred.Ngroups > 0 {
224 if got, want := cred.Groups[0], os.Getgid(); int(got) != int(want) {
225 t.Errorf("gid = %v; want %v", got, want)
226 }
227 }
228 }
229
230 func TestSysctlKinfoProc(t *testing.T) {
231 pid := unix.Getpid()
232 kp, err := unix.SysctlKinfoProc("kern.proc.pid", pid)
233 if err != nil {
234 t.Fatalf("SysctlKinfoProc: %v", err)
235 }
236 if got, want := int(kp.Proc.P_pid), pid; got != want {
237 t.Errorf("got pid %d, want %d", got, want)
238 }
239 }
240
241 func TestSysctlKinfoProcSlice(t *testing.T) {
242 kps, err := unix.SysctlKinfoProcSlice("kern.proc.all")
243 if err != nil {
244 t.Fatalf("SysctlKinfoProc: %v", err)
245 }
246 if len(kps) == 0 {
247 t.Errorf("SysctlKinfoProcSlice: expected at least one process")
248 }
249
250 uid := unix.Getuid()
251 kps, err = unix.SysctlKinfoProcSlice("kern.proc.uid", uid)
252 if err != nil {
253 t.Fatalf("SysctlKinfoProc: %v", err)
254 }
255 if len(kps) == 0 {
256 t.Errorf("SysctlKinfoProcSlice: expected at least one process")
257 }
258
259 for _, kp := range kps {
260 if got, want := int(kp.Eproc.Ucred.Uid), uid; got != want {
261 t.Errorf("process %d: got uid %d, want %d", kp.Proc.P_pid, got, want)
262 }
263 }
264 }
265
View as plain text