modernc.org/libc@v1.24.1/libc_unix.go (about)

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