github.com/afumu/libc@v0.0.6/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 linux || darwin || freebsd || netbsd || openbsd
     6  // +build linux darwin freebsd netbsd openbsd
     7  
     8  package libc // import "github.com/afumu/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  	"github.com/afumu/libc/errno"
    26  	"github.com/afumu/libc/grp"
    27  	"github.com/afumu/libc/poll"
    28  	"github.com/afumu/libc/pwd"
    29  	"github.com/afumu/libc/signal"
    30  	"github.com/afumu/libc/stdio"
    31  	"github.com/afumu/libc/stdlib"
    32  	"github.com/afumu/libc/sys/types"
    33  	ctime "github.com/afumu/libc/time"
    34  	guuid "github.com/google/uuid"
    35  	"golang.org/x/sys/unix"
    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  }