gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

libc_unix.go (22091B)


      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 }