1// Copyright 2009 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 syscall
6
7import "unsafe"
8
9const (
10	_SYS_setgroups  = SYS_SETGROUPS32
11	_SYS_clone3     = 435
12	_SYS_faccessat2 = 439
13	_SYS_fchmodat2  = 452
14)
15
16func setTimespec(sec, nsec int64) Timespec {
17	return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
18}
19
20func setTimeval(sec, usec int64) Timeval {
21	return Timeval{Sec: int32(sec), Usec: int32(usec)}
22}
23
24// 64-bit file system and 32-bit uid calls
25// (386 default is 32-bit file system and 16-bit uid).
26//sys	Dup2(oldfd int, newfd int) (err error)
27//sys	Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
28//sys	Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
29//sys	fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
30//sys	Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
31//sysnb	Getegid() (egid int) = SYS_GETEGID32
32//sysnb	Geteuid() (euid int) = SYS_GETEUID32
33//sysnb	Getgid() (gid int) = SYS_GETGID32
34//sysnb	Getuid() (uid int) = SYS_GETUID32
35//sysnb	InotifyInit() (fd int, err error)
36//sys	Ioperm(from int, num int, on int) (err error)
37//sys	Iopl(level int) (err error)
38//sys	Pause() (err error)
39//sys	pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
40//sys	pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
41//sys	Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
42//sys	sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
43//sys	Setfsgid(gid int) (err error) = SYS_SETFSGID32
44//sys	Setfsuid(uid int) (err error) = SYS_SETFSUID32
45//sys	Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
46//sys	SyncFileRange(fd int, off int64, n int64, flags int) (err error)
47//sys	Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
48//sys	Ustat(dev int, ubuf *Ustat_t) (err error)
49//sysnb	getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
50//sys	Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
51
52//sys	mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
53//sys	EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
54
55func Stat(path string, stat *Stat_t) (err error) {
56	return fstatat(_AT_FDCWD, path, stat, 0)
57}
58
59func Lchown(path string, uid int, gid int) (err error) {
60	return Fchownat(_AT_FDCWD, path, uid, gid, _AT_SYMLINK_NOFOLLOW)
61}
62
63func Lstat(path string, stat *Stat_t) (err error) {
64	return fstatat(_AT_FDCWD, path, stat, _AT_SYMLINK_NOFOLLOW)
65}
66
67func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
68	page := uintptr(offset / 4096)
69	if offset != int64(page)*4096 {
70		return 0, EINVAL
71	}
72	return mmap2(addr, length, prot, flags, fd, page)
73}
74
75type rlimit32 struct {
76	Cur uint32
77	Max uint32
78}
79
80//sysnb getrlimit(resource int, rlim *rlimit32) (err error) = SYS_GETRLIMIT
81
82const rlimInf32 = ^uint32(0)
83const rlimInf64 = ^uint64(0)
84
85func Getrlimit(resource int, rlim *Rlimit) (err error) {
86	err = prlimit(0, resource, nil, rlim)
87	if err != ENOSYS {
88		return err
89	}
90
91	rl := rlimit32{}
92	err = getrlimit(resource, &rl)
93	if err != nil {
94		return
95	}
96
97	if rl.Cur == rlimInf32 {
98		rlim.Cur = rlimInf64
99	} else {
100		rlim.Cur = uint64(rl.Cur)
101	}
102
103	if rl.Max == rlimInf32 {
104		rlim.Max = rlimInf64
105	} else {
106		rlim.Max = uint64(rl.Max)
107	}
108	return
109}
110
111//sysnb setrlimit1(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
112
113func setrlimit(resource int, rlim *Rlimit) (err error) {
114	err = prlimit(0, resource, rlim, nil)
115	if err != ENOSYS {
116		return err
117	}
118
119	rl := rlimit32{}
120	if rlim.Cur == rlimInf64 {
121		rl.Cur = rlimInf32
122	} else if rlim.Cur < uint64(rlimInf32) {
123		rl.Cur = uint32(rlim.Cur)
124	} else {
125		return EINVAL
126	}
127	if rlim.Max == rlimInf64 {
128		rl.Max = rlimInf32
129	} else if rlim.Max < uint64(rlimInf32) {
130		rl.Max = uint32(rlim.Max)
131	} else {
132		return EINVAL
133	}
134
135	return setrlimit1(resource, &rl)
136}
137
138//go:nosplit
139func rawSetrlimit(resource int, rlim *Rlimit) Errno {
140	_, _, errno := RawSyscall6(SYS_PRLIMIT64, 0, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0, 0, 0)
141	if errno != ENOSYS {
142		return errno
143	}
144
145	rl := rlimit32{}
146	if rlim.Cur == rlimInf64 {
147		rl.Cur = rlimInf32
148	} else if rlim.Cur < uint64(rlimInf32) {
149		rl.Cur = uint32(rlim.Cur)
150	} else {
151		return EINVAL
152	}
153	if rlim.Max == rlimInf64 {
154		rl.Max = rlimInf32
155	} else if rlim.Max < uint64(rlimInf32) {
156		rl.Max = uint32(rlim.Max)
157	} else {
158		return EINVAL
159	}
160
161	_, _, errno = RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
162	return errno
163}
164
165// Underlying system call writes to newoffset via pointer.
166// Implemented in assembly to avoid allocation.
167func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
168
169func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
170	newoffset, errno := seek(fd, offset, whence)
171	if errno != 0 {
172		return 0, errno
173	}
174	return newoffset, nil
175}
176
177//sys	futimesat(dirfd int, path string, times *[2]Timeval) (err error)
178//sysnb	Gettimeofday(tv *Timeval) (err error)
179//sysnb	Time(t *Time_t) (tt Time_t, err error)
180//sys	Utime(path string, buf *Utimbuf) (err error)
181//sys	utimes(path string, times *[2]Timeval) (err error)
182
183// On x86 Linux, all the socket calls go through an extra indirection,
184// I think because the 5-register system call interface can't handle
185// the 6-argument calls like sendto and recvfrom. Instead the
186// arguments to the underlying system call are the number below
187// and a pointer to an array of uintptr. We hide the pointer in the
188// socketcall assembly to avoid allocation on every system call.
189
190const (
191	// see linux/net.h
192	_SOCKET      = 1
193	_BIND        = 2
194	_CONNECT     = 3
195	_LISTEN      = 4
196	_ACCEPT      = 5
197	_GETSOCKNAME = 6
198	_GETPEERNAME = 7
199	_SOCKETPAIR  = 8
200	_SEND        = 9
201	_RECV        = 10
202	_SENDTO      = 11
203	_RECVFROM    = 12
204	_SHUTDOWN    = 13
205	_SETSOCKOPT  = 14
206	_GETSOCKOPT  = 15
207	_SENDMSG     = 16
208	_RECVMSG     = 17
209	_ACCEPT4     = 18
210	_RECVMMSG    = 19
211	_SENDMMSG    = 20
212)
213
214func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err Errno)
215func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err Errno)
216
217func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
218	fd, e := socketcall(_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
219	if e != 0 {
220		err = e
221	}
222	return
223}
224
225func getsockname(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
226	_, e := rawsocketcall(_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
227	if e != 0 {
228		err = e
229	}
230	return
231}
232
233func getpeername(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
234	_, e := rawsocketcall(_GETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
235	if e != 0 {
236		err = e
237	}
238	return
239}
240
241func socketpair(domain int, typ int, flags int, fd *[2]int32) (err error) {
242	_, e := rawsocketcall(_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
243	if e != 0 {
244		err = e
245	}
246	return
247}
248
249func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
250	_, e := socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
251	if e != 0 {
252		err = e
253	}
254	return
255}
256
257func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
258	_, e := socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
259	if e != 0 {
260		err = e
261	}
262	return
263}
264
265func socket(domain int, typ int, proto int) (fd int, err error) {
266	fd, e := rawsocketcall(_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
267	if e != 0 {
268		err = e
269	}
270	return
271}
272
273func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
274	_, e := socketcall(_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
275	if e != 0 {
276		err = e
277	}
278	return
279}
280
281func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
282	_, e := socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), vallen, 0)
283	if e != 0 {
284		err = e
285	}
286	return
287}
288
289func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
290	var base uintptr
291	if len(p) > 0 {
292		base = uintptr(unsafe.Pointer(&p[0]))
293	}
294	n, e := socketcall(_RECVFROM, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
295	if e != 0 {
296		err = e
297	}
298	return
299}
300
301func sendto(s int, p []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
302	var base uintptr
303	if len(p) > 0 {
304		base = uintptr(unsafe.Pointer(&p[0]))
305	}
306	_, e := socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(to), uintptr(addrlen))
307	if e != 0 {
308		err = e
309	}
310	return
311}
312
313func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
314	n, e := socketcall(_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
315	if e != 0 {
316		err = e
317	}
318	return
319}
320
321func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
322	n, e := socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
323	if e != 0 {
324		err = e
325	}
326	return
327}
328
329func Listen(s int, n int) (err error) {
330	_, e := socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0)
331	if e != 0 {
332		err = e
333	}
334	return
335}
336
337func Shutdown(s, how int) (err error) {
338	_, e := socketcall(_SHUTDOWN, uintptr(s), uintptr(how), 0, 0, 0, 0)
339	if e != 0 {
340		err = e
341	}
342	return
343}
344
345func Fstatfs(fd int, buf *Statfs_t) (err error) {
346	_, _, e := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
347	if e != 0 {
348		err = e
349	}
350	return
351}
352
353func Statfs(path string, buf *Statfs_t) (err error) {
354	pathp, err := BytePtrFromString(path)
355	if err != nil {
356		return err
357	}
358	_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
359	if e != 0 {
360		err = e
361	}
362	return
363}
364
365func (r *PtraceRegs) PC() uint64 { return uint64(uint32(r.Eip)) }
366
367func (r *PtraceRegs) SetPC(pc uint64) { r.Eip = int32(pc) }
368
369func (iov *Iovec) SetLen(length int) {
370	iov.Len = uint32(length)
371}
372
373func (msghdr *Msghdr) SetControllen(length int) {
374	msghdr.Controllen = uint32(length)
375}
376
377func (cmsg *Cmsghdr) SetLen(length int) {
378	cmsg.Len = uint32(length)
379}
380