aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/syscall/libcall_linux.go
blob: a78af36f70dcac7e0f53c087ea2f968cbc1515d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// GNU/Linux library calls.

package syscall

import "unsafe"

//sys	Openat(dirfd int, path string, flags int, mode uint32) (fd int, errno int)
//openat(dirfd int, path *byte, flags int, mode Mode_t) int

//sys	futimesat(dirfd int, path *byte, times *[2]Timeval) (errno int)
//futimesat(dirfd int, path *byte, times *[2]Timeval) int
func Futimesat(dirfd int, path string, tv []Timeval) (errno int) {
	if len(tv) != 2 {
		return EINVAL
	}
	return futimesat(dirfd, StringBytePtr(path), (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}

func Futimes(fd int, tv []Timeval) (errno int) {
	// Believe it or not, this is the best we can do on GNU/Linux
	// (and is what glibc does).
	return Utimes("/proc/self/fd/"+itoa(fd), tv)
}

//sys	ptrace(request int, pid int, addr uintptr, data uintptr) (errno int)
//ptrace(request int, pid Pid_t, addr *byte, data *byte) _C_long

//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (errno int)
//ptrace(request int, pid Pid_t, addr *byte, data *byte) _C_long

func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno int) {
	// The peek requests are machine-size oriented, so we wrap it
	// to retrieve arbitrary-length data.

	// The ptrace syscall differs from glibc's ptrace.
	// Peeks returns the word in *data, not as the return value.

	var buf [sizeofPtr]byte

	// Leading edge.  PEEKTEXT/PEEKDATA don't require aligned
	// access (PEEKUSER warns that it might), but if we don't
	// align our reads, we might straddle an unmapped page
	// boundary and not get the bytes leading up to the page
	// boundary.
	n := 0
	if addr%sizeofPtr != 0 {
		errno = ptrace(req, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
		if errno != 0 {
			return 0, errno
		}
		n += copy(out, buf[addr%sizeofPtr:])
		out = out[n:]
	}

	// Remainder.
	for len(out) > 0 {
		// We use an internal buffer to gaurantee alignment.
		// It's not documented if this is necessary, but we're paranoid.
		errno = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
		if errno != 0 {
			return n, errno
		}
		copied := copy(out, buf[0:])
		n += copied
		out = out[copied:]
	}

	return n, 0
}

func PtracePeekText(pid int, addr uintptr, out []byte) (count int, errno int) {
	return ptracePeek(PTRACE_PEEKTEXT, pid, addr, out)
}

func PtracePeekData(pid int, addr uintptr, out []byte) (count int, errno int) {
	return ptracePeek(PTRACE_PEEKDATA, pid, addr, out)
}

func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, errno int) {
	// As for ptracePeek, we need to align our accesses to deal
	// with the possibility of straddling an invalid page.

	// Leading edge.
	n := 0
	if addr%sizeofPtr != 0 {
		var buf [sizeofPtr]byte
		errno = ptrace(peekReq, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
		if errno != 0 {
			return 0, errno
		}
		n += copy(buf[addr%sizeofPtr:], data)
		word := *((*uintptr)(unsafe.Pointer(&buf[0])))
		errno = ptrace(pokeReq, pid, addr-addr%sizeofPtr, word)
		if errno != 0 {
			return 0, errno
		}
		data = data[n:]
	}

	// Interior.
	for len(data) > int(sizeofPtr) {
		word := *((*uintptr)(unsafe.Pointer(&data[0])))
		errno = ptrace(pokeReq, pid, addr+uintptr(n), word)
		if errno != 0 {
			return n, errno
		}
		n += int(sizeofPtr)
		data = data[sizeofPtr:]
	}

	// Trailing edge.
	if len(data) > 0 {
		var buf [sizeofPtr]byte
		errno = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
		if errno != 0 {
			return n, errno
		}
		copy(buf[0:], data)
		word := *((*uintptr)(unsafe.Pointer(&buf[0])))
		errno = ptrace(pokeReq, pid, addr+uintptr(n), word)
		if errno != 0 {
			return n, errno
		}
		n += len(data)
	}

	return n, 0
}

func PtracePokeText(pid int, addr uintptr, data []byte) (count int, errno int) {
	return ptracePoke(PTRACE_POKETEXT, PTRACE_PEEKTEXT, pid, addr, data)
}

func PtracePokeData(pid int, addr uintptr, data []byte) (count int, errno int) {
	return ptracePoke(PTRACE_POKEDATA, PTRACE_PEEKDATA, pid, addr, data)
}

func PtraceGetRegs(pid int, regsout *PtraceRegs) (errno int) {
	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
}

func PtraceSetRegs(pid int, regs *PtraceRegs) (errno int) {
	return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
}

func PtraceSetOptions(pid int, options int) (errno int) {
	return ptrace(PTRACE_SETOPTIONS, pid, 0, uintptr(options))
}

func PtraceGetEventMsg(pid int) (msg uint, errno int) {
	var data _C_long
	errno = ptrace(PTRACE_GETEVENTMSG, pid, 0, uintptr(unsafe.Pointer(&data)))
	msg = uint(data)
	return
}

func PtraceCont(pid int, signal int) (errno int) {
	return ptrace(PTRACE_CONT, pid, 0, uintptr(signal))
}

func PtraceSingleStep(pid int) (errno int) { return ptrace(PTRACE_SINGLESTEP, pid, 0, 0) }

func PtraceAttach(pid int) (errno int) { return ptrace(PTRACE_ATTACH, pid, 0, 0) }

func PtraceDetach(pid int) (errno int) { return ptrace(PTRACE_DETACH, pid, 0, 0) }

// FIXME: mksysinfo needs to produce LINUX_REBOOT_MAGIC[12].

// //sys	reboot(magic1 uint, magic2 uint, cmd int, arg string) (errno int)
// //reboot(magic1 uint, magic2 uint, cmd int, arg *byte) int
// func Reboot(cmd int) (errno int) {
// 	return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "")
// }

//sys	Acct(path string) (errno int)
//acct(path *byte) int

// FIXME: mksysinfo Timex
// //sys	Adjtimex(buf *Timex) (state int, errno int)
// //adjtimex(buf *Timex) int

//sys	Faccessat(dirfd int, path string, mode uint32, flags int) (errno int)
//faccessat(dirfd int, pathname *byte, mode int, flags int) int

//sys	Fallocate(fd int, mode uint32, off int64, len int64) (errno int)
//fallocate(fd int, mode int, offset Offset_t, len Offset_t) int

//sys	Fchmodat(dirfd int, path string, mode uint32, flags int) (errno int)
//fchmodat(dirfd int, pathname *byte, mode Mode_t, flags int) int

//sys	Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int)
//fchownat(dirfd int, path *byte, owner Uid_t, group Gid_t, flags int) int

//sys	Flock(fd int, how int) (errno int)
//flock(fd int, how int) int

// FIXME: mksysinfo statfs
// //sys	Fstatfs(fd int, buf *Statfs_t) (errno int)
// //fstatfs(fd int, buf *Statfs_t) int

// FIXME: Only available as a syscall.
// //sysnb	Gettid() (tid int)
// //gettid() Pid_t

//sys	Ioperm(from int, num int, on int) (errno int)
//ioperm(from _C_long, num _C_long, on int) int

//sys	Iopl(level int) (errno int)
//iopl(level int) int

// FIXME: mksysinfo linux_dirent
//    Or just abandon this function.
// //sys	Getdents(fd int, buf []byte) (n int, errno int)
// //getdents64(fd int, buf *byte, count uint)

//sys	InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, errno int)
//inotify_add_watch(fd int, pathname *byte, mask uint32) int

//sysnb	InotifyInit() (fd int, errno int)
//inotify_init() int

//sysnb	InotifyInit1(flags int) (fd int, errno int)
//inotify_init1(flags int) int

//sysnb	InotifyRmWatch(fd int, watchdesc uint32) (success int, errno int)
//inotify_rm_watch(fd int, wd uint32) int

//sys	Klogctl(typ int, buf []byte) (n int, errno int)
//klogctl(typ int, bufp *byte, len int) int

//sys	Mkdirat(dirfd int, path string, mode uint32) (errno int)
//mkdirat(dirfd int, path *byte, mode Mode_t) int

//sys	Mknodat(dirfd int, path string, mode uint32, dev int) (errno int)
//mknodat(dirfd int, path *byte, mode Mode_t, dev _dev_t) int

//sys	PivotRoot(newroot string, putold string) (errno int)
//pivot_root(newroot *byte, putold *byte) int

//sys	Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int)
//renameat(olddirfd int, oldpath *byte, newdirfd int, newpath *byte) int

//sys	sendfile(outfd int, infd int, offset *Offset_t, count int) (written int, errno int)
//sendfile64(outfd int, infd int, offset *Offset_t, count Size_t) Ssize_t
func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
	var soff Offset_t
	var psoff *Offset_t
	if offset != nil {
		psoff = &soff
	}
	written, errno = sendfile(outfd, infd, psoff, count)
	if offset != nil {
		*offset = int64(soff)
	}
	return
}

//sys	Setfsgid(gid int) (errno int)
//setfsgid(gid Gid_t) int

//sys	Setfsuid(uid int) (errno int)
//setfsuid(uid Uid_t) int

//sysnb	Setresgid(rgid int, egid int, sgid int) (errno int)
//setresgid(rgid Gid_t, egid Gid_t, sgid Gid_t) int

//sysnb	Setresuid(ruid int, eguid int, suid int) (errno int)
//setresuid(ruid Uid_t, euid Uid_t, suid Uid_t) int

//sys	splice(rfd int, roff *_loff_t, wfd int, woff *_loff_t, len int, flags int) (n int64, errno int)
//splice(rfd int, roff *_loff_t, wfd int, woff *_loff_t, len Size_t, flags uint) Ssize_t
func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) {
	var lroff _loff_t
	var plroff *_loff_t
	if (roff != nil) {
		plroff = &lroff
	}
	var lwoff _loff_t
	var plwoff *_loff_t
	if (woff != nil) {
		plwoff = &lwoff
	}
	n, errno = splice(rfd, plroff, wfd, plwoff, len, flags)
	if (roff != nil) {
		*roff = int64(lroff)
	}
	if (woff != nil) {
		*woff = int64(lwoff)
	}
	return
}

// FIXME: mksysinfo statfs
// //sys	Statfs(path string, buf *Statfs_t) (errno int)
// //statfs(path *byte, buf *Statfs_t) int

//sys	SyncFileRange(fd int, off int64, n int64, flags int) (errno int)
//sync_file_range(fd int, off Offset_t, n Offset_t, flags uint) int

// FIXME: mksysinfo Sysinfo_t
// //sysnb	Sysinfo(info *Sysinfo_t) (errno int)
// //sysinfo(info *Sysinfo_t) int

//sys	Tee(rfd int, wfd int, len int, flags int) (n int64, errno int)
//tee(rfd int, wfd int, len Size_t, flags uint) Ssize_t

// FIXME: Only available as a syscall.
// //sysnb	Tgkill(tgid int, tid int, sig int) (errno int)
// //tgkill(tgid int, tid int, sig int) int

//sys	unlinkat(dirfd int, path string, flags int) (errno int)
//unlinkat(dirfd int, path *byte, flags int) int

func Unlinkat(dirfd int, path string) (errno int) {
	return unlinkat(dirfd, path, 0)
}

//sys	Unmount(target string, flags int) (errno int) = SYS_UMOUNT2
//umount2(target *byte, flags int) int

//sys	Unshare(flags int) (errno int)
//unshare(flags int) int

// FIXME: mksysinfo Ustat_t
// //sys	Ustat(dev int, ubuf *Ustat_t) (errno int)
// //ustat(dev _dev_t, ubuf *Ustat_t) int