1 | // Copyright 2020 The Libc 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 |
|
---|
5 | //go:build linux || darwin || freebsd || netbsd || openbsd
|
---|
6 | // +build linux darwin freebsd netbsd openbsd
|
---|
7 |
|
---|
8 | package libc // import "modernc.org/libc"
|
---|
9 |
|
---|
10 | import (
|
---|
11 | "bufio"
|
---|
12 | "io/ioutil"
|
---|
13 | "math"
|
---|
14 | "math/rand"
|
---|
15 | "os"
|
---|
16 | gosignal "os/signal"
|
---|
17 | "reflect"
|
---|
18 | "strconv"
|
---|
19 | "strings"
|
---|
20 | "sync"
|
---|
21 | "syscall"
|
---|
22 | "time"
|
---|
23 | "unsafe"
|
---|
24 |
|
---|
25 | guuid "github.com/google/uuid"
|
---|
26 | "golang.org/x/sys/unix"
|
---|
27 | "modernc.org/libc/errno"
|
---|
28 | "modernc.org/libc/grp"
|
---|
29 | "modernc.org/libc/poll"
|
---|
30 | "modernc.org/libc/pwd"
|
---|
31 | "modernc.org/libc/signal"
|
---|
32 | "modernc.org/libc/stdio"
|
---|
33 | "modernc.org/libc/stdlib"
|
---|
34 | "modernc.org/libc/sys/types"
|
---|
35 | ctime "modernc.org/libc/time"
|
---|
36 | )
|
---|
37 |
|
---|
38 | var staticGetpwnam pwd.Passwd
|
---|
39 |
|
---|
40 | func init() {
|
---|
41 | atExit = append(atExit, func() { closePasswd(&staticGetpwnam) })
|
---|
42 | }
|
---|
43 |
|
---|
44 | // sighandler_t signal(int signum, sighandler_t handler);
|
---|
45 | func Xsignal(t *TLS, signum int32, handler uintptr) uintptr { //TODO use sigaction?
|
---|
46 | signalsMu.Lock()
|
---|
47 |
|
---|
48 | defer signalsMu.Unlock()
|
---|
49 |
|
---|
50 | r := signals[signum]
|
---|
51 | signals[signum] = handler
|
---|
52 | switch handler {
|
---|
53 | case signal.SIG_DFL:
|
---|
54 | panic(todo("%v %#x", syscall.Signal(signum), handler))
|
---|
55 | case signal.SIG_IGN:
|
---|
56 | switch r {
|
---|
57 | case signal.SIG_DFL:
|
---|
58 | gosignal.Ignore(syscall.Signal(signum)) //TODO
|
---|
59 | case signal.SIG_IGN:
|
---|
60 | gosignal.Ignore(syscall.Signal(signum))
|
---|
61 | default:
|
---|
62 | panic(todo("%v %#x", syscall.Signal(signum), handler))
|
---|
63 | }
|
---|
64 | default:
|
---|
65 | switch r {
|
---|
66 | case signal.SIG_DFL:
|
---|
67 | c := make(chan os.Signal, 1)
|
---|
68 | gosignal.Notify(c, syscall.Signal(signum))
|
---|
69 | go func() { //TODO mechanism to stop/cancel
|
---|
70 | for {
|
---|
71 | <-c
|
---|
72 | var f func(*TLS, int32)
|
---|
73 | *(*uintptr)(unsafe.Pointer(&f)) = handler
|
---|
74 | tls := NewTLS()
|
---|
75 | f(tls, signum)
|
---|
76 | tls.Close()
|
---|
77 | }
|
---|
78 | }()
|
---|
79 | case signal.SIG_IGN:
|
---|
80 | panic(todo("%v %#x", syscall.Signal(signum), handler))
|
---|
81 | default:
|
---|
82 | panic(todo("%v %#x", syscall.Signal(signum), handler))
|
---|
83 | }
|
---|
84 | }
|
---|
85 | return r
|
---|
86 | }
|
---|
87 |
|
---|
88 | // void rewind(FILE *stream);
|
---|
89 | func Xrewind(t *TLS, stream uintptr) {
|
---|
90 | Xfseek(t, stream, 0, stdio.SEEK_SET)
|
---|
91 | }
|
---|
92 |
|
---|
93 | // int putchar(int c);
|
---|
94 | func Xputchar(t *TLS, c int32) int32 {
|
---|
95 | if _, err := write([]byte{byte(c)}); err != nil {
|
---|
96 | return stdio.EOF
|
---|
97 | }
|
---|
98 |
|
---|
99 | return int32(c)
|
---|
100 | }
|
---|
101 |
|
---|
102 | // int gethostname(char *name, size_t len);
|
---|
103 | func Xgethostname(t *TLS, name uintptr, slen types.Size_t) int32 {
|
---|
104 | if slen < 0 {
|
---|
105 | t.setErrno(errno.EINVAL)
|
---|
106 | return -1
|
---|
107 | }
|
---|
108 |
|
---|
109 | if slen == 0 {
|
---|
110 | return 0
|
---|
111 | }
|
---|
112 |
|
---|
113 | s, err := os.Hostname()
|
---|
114 | if err != nil {
|
---|
115 | panic(todo(""))
|
---|
116 | }
|
---|
117 |
|
---|
118 | n := len(s)
|
---|
119 | if len(s) >= int(slen) {
|
---|
120 | n = int(slen) - 1
|
---|
121 | }
|
---|
122 | sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
---|
123 | copy((*RawMem)(unsafe.Pointer(name))[:n:n], (*RawMem)(unsafe.Pointer(sh.Data))[:n:n])
|
---|
124 | *(*byte)(unsafe.Pointer(name + uintptr(n))) = 0
|
---|
125 | return 0
|
---|
126 | }
|
---|
127 |
|
---|
128 | // int remove(const char *pathname);
|
---|
129 | func Xremove(t *TLS, pathname uintptr) int32 {
|
---|
130 | panic(todo(""))
|
---|
131 | }
|
---|
132 |
|
---|
133 | // long pathconf(const char *path, int name);
|
---|
134 | func Xpathconf(t *TLS, path uintptr, name int32) long {
|
---|
135 | panic(todo(""))
|
---|
136 | }
|
---|
137 |
|
---|
138 | // ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
|
---|
139 | func Xrecvfrom(t *TLS, sockfd int32, buf uintptr, len types.Size_t, flags int32, src_addr, addrlen uintptr) types.Ssize_t {
|
---|
140 | panic(todo(""))
|
---|
141 | }
|
---|
142 |
|
---|
143 | // ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
|
---|
144 | func Xsendto(t *TLS, sockfd int32, buf uintptr, len types.Size_t, flags int32, src_addr uintptr, addrlen socklen_t) types.Ssize_t {
|
---|
145 | panic(todo(""))
|
---|
146 | }
|
---|
147 |
|
---|
148 | // void srand48(long int seedval);
|
---|
149 | func Xsrand48(t *TLS, seedval long) {
|
---|
150 | panic(todo(""))
|
---|
151 | }
|
---|
152 |
|
---|
153 | // long int lrand48(void);
|
---|
154 | func Xlrand48(t *TLS) long {
|
---|
155 | panic(todo(""))
|
---|
156 | }
|
---|
157 |
|
---|
158 | // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
|
---|
159 | func Xsendmsg(t *TLS, sockfd int32, msg uintptr, flags int32) types.Ssize_t {
|
---|
160 | panic(todo(""))
|
---|
161 | }
|
---|
162 |
|
---|
163 | // int poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
---|
164 | func Xpoll(t *TLS, fds uintptr, nfds poll.Nfds_t, timeout int32) int32 {
|
---|
165 | if nfds == 0 {
|
---|
166 | panic(todo(""))
|
---|
167 | }
|
---|
168 |
|
---|
169 | // if dmesgs {
|
---|
170 | // dmesg("%v: %#x %v %v, %+v", origin(1), fds, nfds, timeout, (*[1000]unix.PollFd)(unsafe.Pointer(fds))[:nfds:nfds])
|
---|
171 | // }
|
---|
172 | n, err := unix.Poll((*[1000]unix.PollFd)(unsafe.Pointer(fds))[:nfds:nfds], int(timeout))
|
---|
173 | // if dmesgs {
|
---|
174 | // dmesg("%v: %v %v", origin(1), n, err)
|
---|
175 | // }
|
---|
176 | if err != nil {
|
---|
177 | t.setErrno(err)
|
---|
178 | return -1
|
---|
179 | }
|
---|
180 |
|
---|
181 | return int32(n)
|
---|
182 | }
|
---|
183 |
|
---|
184 | // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
|
---|
185 | func Xrecvmsg(t *TLS, sockfd int32, msg uintptr, flags int32) types.Ssize_t {
|
---|
186 | n, _, err := unix.Syscall(unix.SYS_RECVMSG, uintptr(sockfd), msg, uintptr(flags))
|
---|
187 | if err != 0 {
|
---|
188 | t.setErrno(err)
|
---|
189 | return -1
|
---|
190 | }
|
---|
191 |
|
---|
192 | return types.Ssize_t(n)
|
---|
193 | }
|
---|
194 |
|
---|
195 | // struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg);
|
---|
196 | func X__cmsg_nxthdr(t *TLS, msgh, cmsg uintptr) uintptr {
|
---|
197 | panic(todo(""))
|
---|
198 | }
|
---|
199 |
|
---|
200 | // wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
|
---|
201 | func Xwcschr(t *TLS, wcs uintptr, wc wchar_t) wchar_t {
|
---|
202 | panic(todo(""))
|
---|
203 | }
|
---|
204 |
|
---|
205 | // gid_t getegid(void);
|
---|
206 | func Xgetegid(t *TLS) types.Gid_t {
|
---|
207 | panic(todo(""))
|
---|
208 | }
|
---|
209 |
|
---|
210 | // gid_t getgid(void);
|
---|
211 | func Xgetgid(t *TLS) types.Gid_t {
|
---|
212 | panic(todo(""))
|
---|
213 | }
|
---|
214 |
|
---|
215 | // void *shmat(int shmid, const void *shmaddr, int shmflg);
|
---|
216 | func Xshmat(t *TLS, shmid int32, shmaddr uintptr, shmflg int32) uintptr {
|
---|
217 | panic(todo(""))
|
---|
218 | }
|
---|
219 |
|
---|
220 | // int shmctl(int shmid, int cmd, struct shmid_ds *buf);
|
---|
221 | func Xshmctl(t *TLS, shmid, cmd int32, buf uintptr) int32 {
|
---|
222 | panic(todo(""))
|
---|
223 | }
|
---|
224 |
|
---|
225 | // int shmdt(const void *shmaddr);
|
---|
226 | func Xshmdt(t *TLS, shmaddr uintptr) int32 {
|
---|
227 | panic(todo(""))
|
---|
228 | }
|
---|
229 |
|
---|
230 | // int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
|
---|
231 | func Xgetresuid(t *TLS, ruid, euid, suid uintptr) int32 {
|
---|
232 | panic(todo(""))
|
---|
233 | }
|
---|
234 |
|
---|
235 | // int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
|
---|
236 | func Xgetresgid(t *TLS, rgid, egid, sgid uintptr) int32 {
|
---|
237 | panic(todo(""))
|
---|
238 | }
|
---|
239 |
|
---|
240 | // FILE *tmpfile(void);
|
---|
241 | func Xtmpfile(t *TLS) uintptr {
|
---|
242 | f, err := ioutil.TempFile("", "tmpfile-")
|
---|
243 | if err != nil {
|
---|
244 | t.setErrno(err)
|
---|
245 | return 0
|
---|
246 | }
|
---|
247 |
|
---|
248 | cf := newFile(t, int32(f.Fd()))
|
---|
249 | AtExit(func() {
|
---|
250 | nm := f.Name()
|
---|
251 | file(cf).close(t)
|
---|
252 | os.Remove(nm)
|
---|
253 | })
|
---|
254 |
|
---|
255 | return cf
|
---|
256 | }
|
---|
257 |
|
---|
258 | // FILE *fdopen(int fd, const char *mode);
|
---|
259 | func Xfdopen(t *TLS, fd int32, mode uintptr) uintptr {
|
---|
260 | m := strings.ReplaceAll(GoString(mode), "b", "")
|
---|
261 | switch m {
|
---|
262 | case
|
---|
263 | "a",
|
---|
264 | "a+",
|
---|
265 | "r",
|
---|
266 | "r+",
|
---|
267 | "w",
|
---|
268 | "w+":
|
---|
269 | default:
|
---|
270 | t.setErrno(errno.EINVAL)
|
---|
271 | return 0
|
---|
272 | }
|
---|
273 |
|
---|
274 | if p := newFile(t, fd); p != 0 {
|
---|
275 | return p
|
---|
276 | }
|
---|
277 |
|
---|
278 | t.setErrno(errno.EINVAL)
|
---|
279 | return 0
|
---|
280 | }
|
---|
281 |
|
---|
282 | // struct passwd *getpwnam(const char *name);
|
---|
283 | func Xgetpwnam(t *TLS, name uintptr) uintptr {
|
---|
284 | f, err := os.Open("/etc/passwd")
|
---|
285 | if err != nil {
|
---|
286 | panic(todo("", err))
|
---|
287 | }
|
---|
288 |
|
---|
289 | defer f.Close()
|
---|
290 |
|
---|
291 | sname := GoString(name)
|
---|
292 | sc := bufio.NewScanner(f)
|
---|
293 | for sc.Scan() {
|
---|
294 | s := strings.TrimSpace(sc.Text())
|
---|
295 | if s == "" || strings.HasPrefix(s, "#") {
|
---|
296 | continue
|
---|
297 | }
|
---|
298 |
|
---|
299 | // eg. "root:x:0:0:root:/root:/bin/bash"
|
---|
300 | a := strings.Split(s, ":")
|
---|
301 | if len(a) < 7 {
|
---|
302 | panic(todo(""))
|
---|
303 | }
|
---|
304 |
|
---|
305 | if a[0] == sname {
|
---|
306 | uid, err := strconv.Atoi(a[2])
|
---|
307 | if err != nil {
|
---|
308 | panic(todo(""))
|
---|
309 | }
|
---|
310 |
|
---|
311 | gid, err := strconv.Atoi(a[3])
|
---|
312 | if err != nil {
|
---|
313 | panic(todo(""))
|
---|
314 | }
|
---|
315 |
|
---|
316 | closePasswd(&staticGetpwnam)
|
---|
317 | gecos := a[4]
|
---|
318 | if strings.Contains(gecos, ",") {
|
---|
319 | a := strings.Split(gecos, ",")
|
---|
320 | gecos = a[0]
|
---|
321 | }
|
---|
322 | initPasswd(t, &staticGetpwnam, a[0], a[1], uint32(uid), uint32(gid), gecos, a[5], a[6])
|
---|
323 | return uintptr(unsafe.Pointer(&staticGetpwnam))
|
---|
324 | }
|
---|
325 | }
|
---|
326 |
|
---|
327 | if sc.Err() != nil {
|
---|
328 | panic(todo(""))
|
---|
329 | }
|
---|
330 |
|
---|
331 | return 0
|
---|
332 | }
|
---|
333 |
|
---|
334 | // int getpwnam_r(char *name, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result);
|
---|
335 | func Xgetpwnam_r(t *TLS, name, cpwd, buf uintptr, buflen types.Size_t, result uintptr) int32 {
|
---|
336 | f, err := os.Open("/etc/passwd")
|
---|
337 | if err != nil {
|
---|
338 | panic(todo("", err))
|
---|
339 | }
|
---|
340 |
|
---|
341 | defer f.Close()
|
---|
342 |
|
---|
343 | sname := GoString(name)
|
---|
344 | sc := bufio.NewScanner(f)
|
---|
345 | for sc.Scan() {
|
---|
346 | s := strings.TrimSpace(sc.Text())
|
---|
347 | if s == "" || strings.HasPrefix(s, "#") {
|
---|
348 | continue
|
---|
349 | }
|
---|
350 |
|
---|
351 | // eg. "root:x:0:0:root:/root:/bin/bash"
|
---|
352 | a := strings.Split(s, ":")
|
---|
353 | if len(a) < 7 {
|
---|
354 | panic(todo("%q", s))
|
---|
355 | }
|
---|
356 |
|
---|
357 | if a[0] == sname {
|
---|
358 | uid, err := strconv.Atoi(a[2])
|
---|
359 | if err != nil {
|
---|
360 | panic(todo(""))
|
---|
361 | }
|
---|
362 |
|
---|
363 | gid, err := strconv.Atoi(a[3])
|
---|
364 | if err != nil {
|
---|
365 | panic(todo(""))
|
---|
366 | }
|
---|
367 |
|
---|
368 | gecos := a[4]
|
---|
369 | if strings.Contains(gecos, ",") {
|
---|
370 | a := strings.Split(gecos, ",")
|
---|
371 | gecos = a[0]
|
---|
372 | }
|
---|
373 | var v pwd.Passwd
|
---|
374 | if initPasswd2(t, buf, buflen, &v, a[0], a[1], uint32(uid), uint32(gid), gecos, a[5], a[6]) {
|
---|
375 | *(*pwd.Passwd)(unsafe.Pointer(cpwd)) = v
|
---|
376 | *(*uintptr)(unsafe.Pointer(result)) = cpwd
|
---|
377 | return 0
|
---|
378 | }
|
---|
379 |
|
---|
380 | *(*uintptr)(unsafe.Pointer(result)) = 0
|
---|
381 | return errno.ERANGE
|
---|
382 | }
|
---|
383 | }
|
---|
384 |
|
---|
385 | if sc.Err() != nil {
|
---|
386 | panic(todo(""))
|
---|
387 | }
|
---|
388 |
|
---|
389 | *(*uintptr)(unsafe.Pointer(result)) = 0
|
---|
390 | return 0
|
---|
391 | }
|
---|
392 |
|
---|
393 | func init() {
|
---|
394 | atExit = append(atExit, func() { closeGroup(&staticGetgrgid) })
|
---|
395 | }
|
---|
396 |
|
---|
397 | var staticGetgrgid grp.Group
|
---|
398 |
|
---|
399 | // struct group *getgrgid(gid_t gid);
|
---|
400 | func Xgetgrgid(t *TLS, gid uint32) uintptr {
|
---|
401 | f, err := os.Open("/etc/group")
|
---|
402 | if err != nil {
|
---|
403 | panic(todo(""))
|
---|
404 | }
|
---|
405 |
|
---|
406 | defer f.Close()
|
---|
407 |
|
---|
408 | sid := strconv.Itoa(int(gid))
|
---|
409 | sc := bufio.NewScanner(f)
|
---|
410 | for sc.Scan() {
|
---|
411 | s := strings.TrimSpace(sc.Text())
|
---|
412 | if s == "" || strings.HasPrefix(s, "#") {
|
---|
413 | continue
|
---|
414 | }
|
---|
415 |
|
---|
416 | // eg. "root:x:0:"
|
---|
417 | a := strings.Split(s, ":")
|
---|
418 | if len(a) < 4 {
|
---|
419 | panic(todo("%q", s))
|
---|
420 | }
|
---|
421 |
|
---|
422 | if a[2] == sid {
|
---|
423 | closeGroup(&staticGetgrgid)
|
---|
424 | var names []string
|
---|
425 | if a[3] != "" {
|
---|
426 | names = strings.Split(a[3], ",")
|
---|
427 | }
|
---|
428 | initGroup(t, &staticGetgrgid, a[0], a[1], gid, names)
|
---|
429 | return uintptr(unsafe.Pointer(&staticGetgrgid))
|
---|
430 | }
|
---|
431 | }
|
---|
432 |
|
---|
433 | if sc.Err() != nil {
|
---|
434 | panic(todo(""))
|
---|
435 | }
|
---|
436 |
|
---|
437 | return 0
|
---|
438 | }
|
---|
439 |
|
---|
440 | // int getgrgid_r(gid_t gid, struct group *grp, char *buf, size_t buflen, struct group **result);
|
---|
441 | func Xgetgrgid_r(t *TLS, gid uint32, pGrp, buf uintptr, buflen types.Size_t, result uintptr) int32 {
|
---|
442 | f, err := os.Open("/etc/group")
|
---|
443 | if err != nil {
|
---|
444 | panic(todo(""))
|
---|
445 | }
|
---|
446 |
|
---|
447 | defer f.Close()
|
---|
448 |
|
---|
449 | sid := strconv.Itoa(int(gid))
|
---|
450 | sc := bufio.NewScanner(f)
|
---|
451 | for sc.Scan() {
|
---|
452 | s := strings.TrimSpace(sc.Text())
|
---|
453 | if s == "" || strings.HasPrefix(s, "#") {
|
---|
454 | continue
|
---|
455 | }
|
---|
456 |
|
---|
457 | // eg. "root:x:0:"
|
---|
458 | a := strings.Split(s, ":")
|
---|
459 | if len(a) < 4 {
|
---|
460 | panic(todo("%q", s))
|
---|
461 | }
|
---|
462 |
|
---|
463 | if a[2] == sid {
|
---|
464 | var names []string
|
---|
465 | if a[3] != "" {
|
---|
466 | names = strings.Split(a[3], ",")
|
---|
467 | }
|
---|
468 | var x grp.Group
|
---|
469 | if initGroup2(buf, buflen, &x, a[0], a[1], gid, names) {
|
---|
470 | *(*grp.Group)(unsafe.Pointer(pGrp)) = x
|
---|
471 | *(*uintptr)(unsafe.Pointer(result)) = pGrp
|
---|
472 | return 0
|
---|
473 | }
|
---|
474 |
|
---|
475 | *(*uintptr)(unsafe.Pointer(result)) = 0
|
---|
476 | return 0
|
---|
477 | }
|
---|
478 | }
|
---|
479 |
|
---|
480 | if sc.Err() != nil {
|
---|
481 | panic(todo(""))
|
---|
482 | }
|
---|
483 |
|
---|
484 | *(*uintptr)(unsafe.Pointer(result)) = 0
|
---|
485 | return 0
|
---|
486 | }
|
---|
487 |
|
---|
488 | func initPasswd2(t *TLS, buf uintptr, buflen types.Size_t, p *pwd.Passwd, name, pwd string, uid, gid uint32, gecos, dir, shell string) bool {
|
---|
489 | p.Fpw_name, buf, buflen = bufString(buf, buflen, name)
|
---|
490 | if buf == 0 {
|
---|
491 | return false
|
---|
492 | }
|
---|
493 |
|
---|
494 | p.Fpw_passwd, buf, buflen = bufString(buf, buflen, pwd)
|
---|
495 | if buf == 0 {
|
---|
496 | return false
|
---|
497 | }
|
---|
498 |
|
---|
499 | p.Fpw_uid = uid
|
---|
500 | p.Fpw_gid = gid
|
---|
501 | if buf == 0 {
|
---|
502 | return false
|
---|
503 | }
|
---|
504 |
|
---|
505 | p.Fpw_gecos, buf, buflen = bufString(buf, buflen, gecos)
|
---|
506 | if buf == 0 {
|
---|
507 | return false
|
---|
508 | }
|
---|
509 |
|
---|
510 | p.Fpw_dir, buf, buflen = bufString(buf, buflen, dir)
|
---|
511 | if buf == 0 {
|
---|
512 | return false
|
---|
513 | }
|
---|
514 |
|
---|
515 | p.Fpw_shell, buf, buflen = bufString(buf, buflen, shell)
|
---|
516 | if buf == 0 {
|
---|
517 | return false
|
---|
518 | }
|
---|
519 |
|
---|
520 | return true
|
---|
521 | }
|
---|
522 |
|
---|
523 | func bufString(buf uintptr, buflen types.Size_t, s string) (uintptr, uintptr, types.Size_t) {
|
---|
524 | buf0 := buf
|
---|
525 | rq := len(s) + 1
|
---|
526 | if rq > int(buflen) {
|
---|
527 | return 0, 0, 0
|
---|
528 | }
|
---|
529 |
|
---|
530 | copy((*RawMem)(unsafe.Pointer(buf))[:len(s):len(s)], s)
|
---|
531 | buf += uintptr(len(s))
|
---|
532 | *(*byte)(unsafe.Pointer(buf)) = 0
|
---|
533 | return buf0, buf + 1, buflen - types.Size_t(rq)
|
---|
534 | }
|
---|
535 |
|
---|
536 | func closeGroup(p *grp.Group) {
|
---|
537 | Xfree(nil, p.Fgr_name)
|
---|
538 | Xfree(nil, p.Fgr_passwd)
|
---|
539 | if p := p.Fgr_mem; p != 0 {
|
---|
540 | for {
|
---|
541 | q := *(*uintptr)(unsafe.Pointer(p))
|
---|
542 | if q == 0 {
|
---|
543 | break
|
---|
544 | }
|
---|
545 |
|
---|
546 | Xfree(nil, q)
|
---|
547 | p += unsafe.Sizeof(uintptr(0))
|
---|
548 | }
|
---|
549 | }
|
---|
550 | *p = grp.Group{}
|
---|
551 | }
|
---|
552 |
|
---|
553 | func initGroup(t *TLS, p *grp.Group, name, pwd string, gid uint32, names []string) {
|
---|
554 | p.Fgr_name = cString(t, name)
|
---|
555 | p.Fgr_passwd = cString(t, pwd)
|
---|
556 | p.Fgr_gid = gid
|
---|
557 | a := Xcalloc(t, 1, types.Size_t(unsafe.Sizeof(uintptr(0)))*types.Size_t((len(names)+1)))
|
---|
558 | if a == 0 {
|
---|
559 | panic("OOM")
|
---|
560 | }
|
---|
561 |
|
---|
562 | for p := a; len(names) != 0; p += unsafe.Sizeof(uintptr(0)) {
|
---|
563 | *(*uintptr)(unsafe.Pointer(p)) = cString(t, names[0])
|
---|
564 | names = names[1:]
|
---|
565 | }
|
---|
566 | p.Fgr_mem = a
|
---|
567 | }
|
---|
568 |
|
---|
569 | func initGroup2(buf uintptr, buflen types.Size_t, p *grp.Group, name, pwd string, gid uint32, names []string) bool {
|
---|
570 | p.Fgr_name, buf, buflen = bufString(buf, buflen, name)
|
---|
571 | if buf == 0 {
|
---|
572 | return false
|
---|
573 | }
|
---|
574 |
|
---|
575 | p.Fgr_passwd, buf, buflen = bufString(buf, buflen, pwd)
|
---|
576 | if buf == 0 {
|
---|
577 | return false
|
---|
578 | }
|
---|
579 |
|
---|
580 | p.Fgr_gid = gid
|
---|
581 | rq := unsafe.Sizeof(uintptr(0)) * uintptr(len(names)+1)
|
---|
582 | if rq > uintptr(buflen) {
|
---|
583 | return false
|
---|
584 | }
|
---|
585 |
|
---|
586 | a := buf
|
---|
587 | buf += rq
|
---|
588 | for ; len(names) != 0; buf += unsafe.Sizeof(uintptr(0)) {
|
---|
589 | if len(names[0])+1 > int(buflen) {
|
---|
590 | return false
|
---|
591 | }
|
---|
592 |
|
---|
593 | *(*uintptr)(unsafe.Pointer(buf)), buf, buflen = bufString(buf, buflen, names[0])
|
---|
594 | names = names[1:]
|
---|
595 | }
|
---|
596 | *(*uintptr)(unsafe.Pointer(buf)) = 0
|
---|
597 | p.Fgr_mem = a
|
---|
598 | return true
|
---|
599 | }
|
---|
600 |
|
---|
601 | func init() {
|
---|
602 | atExit = append(atExit, func() { closeGroup(&staticGetgrgid) })
|
---|
603 | }
|
---|
604 |
|
---|
605 | var staticGetpwuid pwd.Passwd
|
---|
606 |
|
---|
607 | func init() {
|
---|
608 | atExit = append(atExit, func() { closePasswd(&staticGetpwuid) })
|
---|
609 | }
|
---|
610 |
|
---|
611 | func closePasswd(p *pwd.Passwd) {
|
---|
612 | Xfree(nil, p.Fpw_name)
|
---|
613 | Xfree(nil, p.Fpw_passwd)
|
---|
614 | Xfree(nil, p.Fpw_gecos)
|
---|
615 | Xfree(nil, p.Fpw_dir)
|
---|
616 | Xfree(nil, p.Fpw_shell)
|
---|
617 | *p = pwd.Passwd{}
|
---|
618 | }
|
---|
619 |
|
---|
620 | var staticGetgrnam grp.Group
|
---|
621 |
|
---|
622 | func init() {
|
---|
623 | atExit = append(atExit, func() { closeGroup(&staticGetgrnam) })
|
---|
624 | }
|
---|
625 |
|
---|
626 | // struct passwd *getpwuid(uid_t uid);
|
---|
627 | func Xgetpwuid(t *TLS, uid uint32) uintptr {
|
---|
628 | f, err := os.Open("/etc/passwd")
|
---|
629 | if err != nil {
|
---|
630 | panic(todo("", err))
|
---|
631 | }
|
---|
632 |
|
---|
633 | defer f.Close()
|
---|
634 |
|
---|
635 | sid := strconv.Itoa(int(uid))
|
---|
636 | sc := bufio.NewScanner(f)
|
---|
637 | for sc.Scan() {
|
---|
638 | s := strings.TrimSpace(sc.Text())
|
---|
639 | if len(s) == 0 || strings.HasPrefix(s, "#") {
|
---|
640 | continue
|
---|
641 | }
|
---|
642 |
|
---|
643 | // eg. "root:x:0:0:root:/root:/bin/bash"
|
---|
644 | a := strings.Split(s, ":")
|
---|
645 | if len(a) < 7 {
|
---|
646 | panic(todo("%q", s))
|
---|
647 | }
|
---|
648 |
|
---|
649 | if a[2] == sid {
|
---|
650 | uid, err := strconv.Atoi(a[2])
|
---|
651 | if err != nil {
|
---|
652 | panic(todo(""))
|
---|
653 | }
|
---|
654 |
|
---|
655 | gid, err := strconv.Atoi(a[3])
|
---|
656 | if err != nil {
|
---|
657 | panic(todo(""))
|
---|
658 | }
|
---|
659 |
|
---|
660 | closePasswd(&staticGetpwuid)
|
---|
661 | gecos := a[4]
|
---|
662 | if strings.Contains(gecos, ",") {
|
---|
663 | a := strings.Split(gecos, ",")
|
---|
664 | gecos = a[0]
|
---|
665 | }
|
---|
666 | initPasswd(t, &staticGetpwuid, a[0], a[1], uint32(uid), uint32(gid), gecos, a[5], a[6])
|
---|
667 | return uintptr(unsafe.Pointer(&staticGetpwuid))
|
---|
668 | }
|
---|
669 | }
|
---|
670 |
|
---|
671 | if sc.Err() != nil {
|
---|
672 | panic(todo(""))
|
---|
673 | }
|
---|
674 |
|
---|
675 | return 0
|
---|
676 | }
|
---|
677 |
|
---|
678 | func initPasswd(t *TLS, p *pwd.Passwd, name, pwd string, uid, gid uint32, gecos, dir, shell string) {
|
---|
679 | p.Fpw_name = cString(t, name)
|
---|
680 | p.Fpw_passwd = cString(t, pwd)
|
---|
681 | p.Fpw_uid = uid
|
---|
682 | p.Fpw_gid = gid
|
---|
683 | p.Fpw_gecos = cString(t, gecos)
|
---|
684 | p.Fpw_dir = cString(t, dir)
|
---|
685 | p.Fpw_shell = cString(t, shell)
|
---|
686 | }
|
---|
687 |
|
---|
688 | // struct group *getgrnam(const char *name);
|
---|
689 | func Xgetgrnam(t *TLS, name uintptr) uintptr {
|
---|
690 | f, err := os.Open("/etc/group")
|
---|
691 | if err != nil {
|
---|
692 | panic(todo(""))
|
---|
693 | }
|
---|
694 |
|
---|
695 | defer f.Close()
|
---|
696 |
|
---|
697 | sname := GoString(name)
|
---|
698 | sc := bufio.NewScanner(f)
|
---|
699 | for sc.Scan() {
|
---|
700 | s := strings.TrimSpace(sc.Text())
|
---|
701 | if len(s) == 0 || strings.HasPrefix(s, "#") {
|
---|
702 | continue
|
---|
703 | }
|
---|
704 |
|
---|
705 | // eg. "root:x:0:"
|
---|
706 | a := strings.Split(s, ":")
|
---|
707 | if len(a) < 4 {
|
---|
708 | panic(todo("%q", s))
|
---|
709 | }
|
---|
710 |
|
---|
711 | if a[0] == sname {
|
---|
712 | closeGroup(&staticGetgrnam)
|
---|
713 | gid, err := strconv.Atoi(a[2])
|
---|
714 | if err != nil {
|
---|
715 | panic(todo(""))
|
---|
716 | }
|
---|
717 |
|
---|
718 | var names []string
|
---|
719 | if a[3] != "" {
|
---|
720 | names = strings.Split(a[3], ",")
|
---|
721 | }
|
---|
722 | initGroup(t, &staticGetgrnam, a[0], a[1], uint32(gid), names)
|
---|
723 | return uintptr(unsafe.Pointer(&staticGetgrnam))
|
---|
724 | }
|
---|
725 | }
|
---|
726 |
|
---|
727 | if sc.Err() != nil {
|
---|
728 | panic(todo(""))
|
---|
729 | }
|
---|
730 |
|
---|
731 | return 0
|
---|
732 | }
|
---|
733 |
|
---|
734 | // int getgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result);
|
---|
735 | func Xgetgrnam_r(t *TLS, name, pGrp, buf uintptr, buflen types.Size_t, result uintptr) int32 {
|
---|
736 | f, err := os.Open("/etc/group")
|
---|
737 | if err != nil {
|
---|
738 | panic(todo(""))
|
---|
739 | }
|
---|
740 |
|
---|
741 | defer f.Close()
|
---|
742 |
|
---|
743 | sname := GoString(name)
|
---|
744 | sc := bufio.NewScanner(f)
|
---|
745 | for sc.Scan() {
|
---|
746 | s := strings.TrimSpace(sc.Text())
|
---|
747 | if len(s) == 0 || strings.HasPrefix(s, "#") {
|
---|
748 | continue
|
---|
749 | }
|
---|
750 |
|
---|
751 | // eg. "root:x:0:"
|
---|
752 | a := strings.Split(s, ":")
|
---|
753 | if len(a) < 4 {
|
---|
754 | panic(todo("%q", s))
|
---|
755 | }
|
---|
756 |
|
---|
757 | if a[0] == sname {
|
---|
758 | gid, err := strconv.Atoi(a[2])
|
---|
759 | if err != nil {
|
---|
760 | panic(todo(""))
|
---|
761 | }
|
---|
762 |
|
---|
763 | var names []string
|
---|
764 | if a[3] != "" {
|
---|
765 | names = strings.Split(a[3], ",")
|
---|
766 | }
|
---|
767 | var x grp.Group
|
---|
768 | if initGroup2(buf, buflen, &x, a[0], a[1], uint32(gid), names) {
|
---|
769 | *(*grp.Group)(unsafe.Pointer(pGrp)) = x
|
---|
770 | *(*uintptr)(unsafe.Pointer(result)) = pGrp
|
---|
771 | return 0
|
---|
772 | }
|
---|
773 |
|
---|
774 | *(*uintptr)(unsafe.Pointer(result)) = 0
|
---|
775 | return 0
|
---|
776 | }
|
---|
777 | }
|
---|
778 |
|
---|
779 | if sc.Err() != nil {
|
---|
780 | panic(todo(""))
|
---|
781 | }
|
---|
782 |
|
---|
783 | *(*uintptr)(unsafe.Pointer(result)) = 0
|
---|
784 | return 0
|
---|
785 | }
|
---|
786 |
|
---|
787 | // int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result);
|
---|
788 | func Xgetpwuid_r(t *TLS, uid types.Uid_t, cpwd, buf uintptr, buflen types.Size_t, result uintptr) int32 {
|
---|
789 | f, err := os.Open("/etc/passwd")
|
---|
790 | if err != nil {
|
---|
791 | panic(todo("", err))
|
---|
792 | }
|
---|
793 |
|
---|
794 | defer f.Close()
|
---|
795 |
|
---|
796 | sid := strconv.Itoa(int(uid))
|
---|
797 | sc := bufio.NewScanner(f)
|
---|
798 | for sc.Scan() {
|
---|
799 | s := strings.TrimSpace(sc.Text())
|
---|
800 | if len(s) == 0 || strings.HasPrefix(s, "#") {
|
---|
801 | continue
|
---|
802 | }
|
---|
803 |
|
---|
804 | // eg. "root:x:0:0:root:/root:/bin/bash"
|
---|
805 | a := strings.Split(s, ":")
|
---|
806 | if len(a) < 7 {
|
---|
807 | panic(todo("%q", s))
|
---|
808 | }
|
---|
809 |
|
---|
810 | if a[2] == sid {
|
---|
811 | uid, err := strconv.Atoi(a[2])
|
---|
812 | if err != nil {
|
---|
813 | panic(todo(""))
|
---|
814 | }
|
---|
815 |
|
---|
816 | gid, err := strconv.Atoi(a[3])
|
---|
817 | if err != nil {
|
---|
818 | panic(todo(""))
|
---|
819 | }
|
---|
820 |
|
---|
821 | gecos := a[4]
|
---|
822 | if strings.Contains(gecos, ",") {
|
---|
823 | a := strings.Split(gecos, ",")
|
---|
824 | gecos = a[0]
|
---|
825 | }
|
---|
826 | var v pwd.Passwd
|
---|
827 | if initPasswd2(t, buf, buflen, &v, a[0], a[1], uint32(uid), uint32(gid), gecos, a[5], a[6]) {
|
---|
828 | *(*pwd.Passwd)(unsafe.Pointer(cpwd)) = v
|
---|
829 | *(*uintptr)(unsafe.Pointer(result)) = cpwd
|
---|
830 | return 0
|
---|
831 | }
|
---|
832 |
|
---|
833 | *(*uintptr)(unsafe.Pointer(result)) = 0
|
---|
834 | return errno.ERANGE
|
---|
835 | }
|
---|
836 | }
|
---|
837 |
|
---|
838 | if sc.Err() != nil {
|
---|
839 | panic(todo(""))
|
---|
840 | }
|
---|
841 |
|
---|
842 | *(*uintptr)(unsafe.Pointer(result)) = 0
|
---|
843 | return 0
|
---|
844 | }
|
---|
845 |
|
---|
846 | // int mkostemp(char *template, int flags);
|
---|
847 | func Xmkostemp(t *TLS, template uintptr, flags int32) int32 {
|
---|
848 | len := uintptr(Xstrlen(t, template))
|
---|
849 | x := template + uintptr(len-6)
|
---|
850 | for i := uintptr(0); i < 6; i++ {
|
---|
851 | if *(*byte)(unsafe.Pointer(x + i)) != 'X' {
|
---|
852 | t.setErrno(errno.EINVAL)
|
---|
853 | return -1
|
---|
854 | }
|
---|
855 | }
|
---|
856 |
|
---|
857 | fd, err := tempFile(template, x, flags)
|
---|
858 | if err != nil {
|
---|
859 | t.setErrno(err)
|
---|
860 | return -1
|
---|
861 | }
|
---|
862 |
|
---|
863 | return int32(fd)
|
---|
864 | }
|
---|
865 |
|
---|
866 | // void uuid_generate_random(uuid_t out);
|
---|
867 | func Xuuid_generate_random(t *TLS, out uintptr) {
|
---|
868 | x := guuid.New()
|
---|
869 | copy((*RawMem)(unsafe.Pointer(out))[:], x[:])
|
---|
870 | }
|
---|
871 |
|
---|
872 | // void uuid_unparse(uuid_t uu, char *out);
|
---|
873 | func Xuuid_unparse(t *TLS, uu, out uintptr) {
|
---|
874 | s := (*guuid.UUID)(unsafe.Pointer(uu)).String()
|
---|
875 | copy((*RawMem)(unsafe.Pointer(out))[:], s)
|
---|
876 | *(*byte)(unsafe.Pointer(out + uintptr(len(s)))) = 0
|
---|
877 | }
|
---|
878 |
|
---|
879 | var staticRandomData = &rand.Rand{}
|
---|
880 |
|
---|
881 | // char *initstate(unsigned seed, char *state, size_t size);
|
---|
882 | func Xinitstate(t *TLS, seed uint32, statebuf uintptr, statelen types.Size_t) uintptr {
|
---|
883 | staticRandomData = rand.New(rand.NewSource(int64(seed)))
|
---|
884 | return 0
|
---|
885 | }
|
---|
886 |
|
---|
887 | // char *setstate(const char *state);
|
---|
888 | func Xsetstate(t *TLS, state uintptr) uintptr {
|
---|
889 | t.setErrno(errno.EINVAL) //TODO
|
---|
890 | return 0
|
---|
891 | }
|
---|
892 |
|
---|
893 | // The initstate_r() function is like initstate(3) except that it initializes
|
---|
894 | // the state in the object pointed to by buf, rather than initializing the
|
---|
895 | // global state variable. Before calling this function, the buf.state field
|
---|
896 | // must be initialized to NULL. The initstate_r() function records a pointer
|
---|
897 | // to the statebuf argument inside the structure pointed to by buf. Thus,
|
---|
898 | // state‐ buf should not be deallocated so long as buf is still in use. (So,
|
---|
899 | // statebuf should typically be allocated as a static variable, or allocated on
|
---|
900 | // the heap using malloc(3) or similar.)
|
---|
901 | //
|
---|
902 | // char *initstate_r(unsigned int seed, char *statebuf, size_t statelen, struct random_data *buf);
|
---|
903 | func Xinitstate_r(t *TLS, seed uint32, statebuf uintptr, statelen types.Size_t, buf uintptr) int32 {
|
---|
904 | if buf == 0 {
|
---|
905 | panic(todo(""))
|
---|
906 | }
|
---|
907 |
|
---|
908 | randomDataMu.Lock()
|
---|
909 |
|
---|
910 | defer randomDataMu.Unlock()
|
---|
911 |
|
---|
912 | randomData[buf] = rand.New(rand.NewSource(int64(seed)))
|
---|
913 | return 0
|
---|
914 | }
|
---|
915 |
|
---|
916 | var (
|
---|
917 | randomData = map[uintptr]*rand.Rand{}
|
---|
918 | randomDataMu sync.Mutex
|
---|
919 | )
|
---|
920 |
|
---|
921 | // int mkstemps(char *template, int suffixlen);
|
---|
922 | func Xmkstemps(t *TLS, template uintptr, suffixlen int32) int32 {
|
---|
923 | return Xmkstemps64(t, template, suffixlen)
|
---|
924 | }
|
---|
925 |
|
---|
926 | // int mkstemps(char *template, int suffixlen);
|
---|
927 | func Xmkstemps64(t *TLS, template uintptr, suffixlen int32) int32 {
|
---|
928 | len := uintptr(Xstrlen(t, template))
|
---|
929 | x := template + uintptr(len-6) - uintptr(suffixlen)
|
---|
930 | for i := uintptr(0); i < 6; i++ {
|
---|
931 | if *(*byte)(unsafe.Pointer(x + i)) != 'X' {
|
---|
932 | t.setErrno(errno.EINVAL)
|
---|
933 | return -1
|
---|
934 | }
|
---|
935 | }
|
---|
936 |
|
---|
937 | fd, err := tempFile(template, x, 0)
|
---|
938 | if err != nil {
|
---|
939 | t.setErrno(err)
|
---|
940 | return -1
|
---|
941 | }
|
---|
942 |
|
---|
943 | return int32(fd)
|
---|
944 | }
|
---|
945 |
|
---|
946 | // int mkstemp(char *template);
|
---|
947 | func Xmkstemp(t *TLS, template uintptr) int32 {
|
---|
948 | return Xmkstemp64(t, template)
|
---|
949 | }
|
---|
950 |
|
---|
951 | // int mkstemp(char *template);
|
---|
952 | func Xmkstemp64(t *TLS, template uintptr) int32 {
|
---|
953 | return Xmkstemps64(t, template, 0)
|
---|
954 | }
|
---|
955 |
|
---|
956 | // int random_r(struct random_data *buf, int32_t *result);
|
---|
957 | func Xrandom_r(t *TLS, buf, result uintptr) int32 {
|
---|
958 | randomDataMu.Lock()
|
---|
959 |
|
---|
960 | defer randomDataMu.Unlock()
|
---|
961 |
|
---|
962 | mr := randomData[buf]
|
---|
963 | if stdlib.RAND_MAX != math.MaxInt32 {
|
---|
964 | panic(todo(""))
|
---|
965 | }
|
---|
966 | *(*int32)(unsafe.Pointer(result)) = mr.Int31()
|
---|
967 | return 0
|
---|
968 | }
|
---|
969 |
|
---|
970 | // int strerror_r(int errnum, char *buf, size_t buflen);
|
---|
971 | func Xstrerror_r(t *TLS, errnum int32, buf uintptr, buflen size_t) int32 {
|
---|
972 | panic(todo(""))
|
---|
973 | }
|
---|
974 |
|
---|
975 | // void endpwent(void);
|
---|
976 | func Xendpwent(t *TLS) {
|
---|
977 | // nop
|
---|
978 | }
|
---|
979 |
|
---|
980 | var ctimeStaticBuf [32]byte
|
---|
981 |
|
---|
982 | // char *ctime(const time_t *timep);
|
---|
983 | func Xctime(t *TLS, timep uintptr) uintptr {
|
---|
984 | return Xctime_r(t, timep, uintptr(unsafe.Pointer(&ctimeStaticBuf[0])))
|
---|
985 | }
|
---|
986 |
|
---|
987 | // char *ctime_r(const time_t *timep, char *buf);
|
---|
988 | func Xctime_r(t *TLS, timep, buf uintptr) uintptr {
|
---|
989 | ut := *(*ctime.Time_t)(unsafe.Pointer(timep))
|
---|
990 | tm := time.Unix(int64(ut), 0).Local()
|
---|
991 | s := tm.Format(time.ANSIC) + "\n\x00"
|
---|
992 | copy((*RawMem)(unsafe.Pointer(buf))[:26:26], s)
|
---|
993 | return buf
|
---|
994 | }
|
---|