github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/syscall/syscall_libc.go (about)

     1  //go:build darwin || nintendoswitch || wasi || wasip1
     2  
     3  package syscall
     4  
     5  import (
     6  	"unsafe"
     7  )
     8  
     9  type sliceHeader struct {
    10  	buf *byte
    11  	len uintptr
    12  	cap uintptr
    13  }
    14  
    15  func Close(fd int) (err error) {
    16  	if libc_close(int32(fd)) < 0 {
    17  		err = getErrno()
    18  	}
    19  	return
    20  }
    21  
    22  func Dup(fd int) (fd2 int, err error) {
    23  	fd2 = int(libc_dup(int32(fd)))
    24  	if fd2 < 0 {
    25  		err = getErrno()
    26  	}
    27  	return
    28  }
    29  
    30  func Write(fd int, p []byte) (n int, err error) {
    31  	buf, count := splitSlice(p)
    32  	n = libc_write(int32(fd), buf, uint(count))
    33  	if n < 0 {
    34  		err = getErrno()
    35  	}
    36  	return
    37  }
    38  
    39  func Read(fd int, p []byte) (n int, err error) {
    40  	buf, count := splitSlice(p)
    41  	n = libc_read(int32(fd), buf, uint(count))
    42  	if n < 0 {
    43  		err = getErrno()
    44  	}
    45  	return
    46  }
    47  
    48  func Pread(fd int, p []byte, offset int64) (n int, err error) {
    49  	buf, count := splitSlice(p)
    50  	n = libc_pread(int32(fd), buf, uint(count), offset)
    51  	if n < 0 {
    52  		err = getErrno()
    53  	}
    54  	return
    55  }
    56  
    57  func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
    58  	buf, count := splitSlice(p)
    59  	n = libc_pwrite(int32(fd), buf, uint(count), offset)
    60  	if n < 0 {
    61  		err = getErrno()
    62  	}
    63  	return
    64  }
    65  
    66  func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
    67  	newoffset = libc_lseek(int32(fd), offset, whence)
    68  	if newoffset < 0 {
    69  		err = getErrno()
    70  	}
    71  	return
    72  }
    73  
    74  func Open(path string, flag int, mode uint32) (fd int, err error) {
    75  	data := cstring(path)
    76  	fd = int(libc_open(&data[0], int32(flag), mode))
    77  	if fd < 0 {
    78  		err = getErrno()
    79  	}
    80  	return
    81  }
    82  
    83  func Fsync(fd int) (err error) {
    84  	if libc_fsync(int32(fd)) < 0 {
    85  		err = getErrno()
    86  	}
    87  	return
    88  }
    89  
    90  func Readlink(path string, p []byte) (n int, err error) {
    91  	data := cstring(path)
    92  	buf, count := splitSlice(p)
    93  	n = libc_readlink(&data[0], buf, uint(count))
    94  	if n < 0 {
    95  		err = getErrno()
    96  	}
    97  	return
    98  }
    99  
   100  func Chdir(path string) (err error) {
   101  	data := cstring(path)
   102  	fail := int(libc_chdir(&data[0]))
   103  	if fail < 0 {
   104  		err = getErrno()
   105  	}
   106  	return
   107  }
   108  
   109  func Mkdir(path string, mode uint32) (err error) {
   110  	data := cstring(path)
   111  	fail := int(libc_mkdir(&data[0], mode))
   112  	if fail < 0 {
   113  		err = getErrno()
   114  	}
   115  	return
   116  }
   117  
   118  func Rmdir(path string) (err error) {
   119  	data := cstring(path)
   120  	fail := int(libc_rmdir(&data[0]))
   121  	if fail < 0 {
   122  		err = getErrno()
   123  	}
   124  	return
   125  }
   126  
   127  func Rename(from, to string) (err error) {
   128  	fromdata := cstring(from)
   129  	todata := cstring(to)
   130  	fail := int(libc_rename(&fromdata[0], &todata[0]))
   131  	if fail < 0 {
   132  		err = getErrno()
   133  	}
   134  	return
   135  }
   136  
   137  func Symlink(from, to string) (err error) {
   138  	fromdata := cstring(from)
   139  	todata := cstring(to)
   140  	fail := int(libc_symlink(&fromdata[0], &todata[0]))
   141  	if fail < 0 {
   142  		err = getErrno()
   143  	}
   144  	return
   145  }
   146  
   147  func Unlink(path string) (err error) {
   148  	data := cstring(path)
   149  	fail := int(libc_unlink(&data[0]))
   150  	if fail < 0 {
   151  		err = getErrno()
   152  	}
   153  	return
   154  }
   155  
   156  func Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
   157  
   158  func Kill(pid int, sig Signal) (err error) {
   159  	return ENOSYS // TODO
   160  }
   161  
   162  type SysProcAttr struct{}
   163  
   164  // TODO
   165  type WaitStatus uint32
   166  
   167  func (w WaitStatus) Exited() bool       { return false }
   168  func (w WaitStatus) ExitStatus() int    { return 0 }
   169  func (w WaitStatus) Signaled() bool     { return false }
   170  func (w WaitStatus) Signal() Signal     { return 0 }
   171  func (w WaitStatus) CoreDump() bool     { return false }
   172  func (w WaitStatus) Stopped() bool      { return false }
   173  func (w WaitStatus) Continued() bool    { return false }
   174  func (w WaitStatus) StopSignal() Signal { return 0 }
   175  func (w WaitStatus) TrapCause() int     { return 0 }
   176  
   177  func Getenv(key string) (value string, found bool) {
   178  	data := cstring(key)
   179  	raw := libc_getenv(&data[0])
   180  	if raw == nil {
   181  		return "", false
   182  	}
   183  
   184  	ptr := uintptr(unsafe.Pointer(raw))
   185  	for size := uintptr(0); ; size++ {
   186  		v := *(*byte)(unsafe.Pointer(ptr))
   187  		if v == 0 {
   188  			src := *(*[]byte)(unsafe.Pointer(&sliceHeader{buf: raw, len: size, cap: size}))
   189  			return string(src), true
   190  		}
   191  		ptr += unsafe.Sizeof(byte(0))
   192  	}
   193  }
   194  
   195  func Setenv(key, val string) (err error) {
   196  	if len(key) == 0 {
   197  		return EINVAL
   198  	}
   199  	for i := 0; i < len(key); i++ {
   200  		if key[i] == '=' || key[i] == 0 {
   201  			return EINVAL
   202  		}
   203  	}
   204  	for i := 0; i < len(val); i++ {
   205  		if val[i] == 0 {
   206  			return EINVAL
   207  		}
   208  	}
   209  	runtimeSetenv(key, val)
   210  	return
   211  }
   212  
   213  func Unsetenv(key string) (err error) {
   214  	runtimeUnsetenv(key)
   215  	return
   216  }
   217  
   218  func Clearenv() {
   219  	for _, s := range Environ() {
   220  		for j := 0; j < len(s); j++ {
   221  			if s[j] == '=' {
   222  				Unsetenv(s[0:j])
   223  				break
   224  			}
   225  		}
   226  	}
   227  }
   228  
   229  func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
   230  	addr := libc_mmap(nil, uintptr(length), int32(prot), int32(flags), int32(fd), uintptr(offset))
   231  	if addr == unsafe.Pointer(^uintptr(0)) {
   232  		return nil, getErrno()
   233  	}
   234  	return (*[1 << 30]byte)(addr)[:length:length], nil
   235  }
   236  
   237  func Munmap(b []byte) (err error) {
   238  	errCode := libc_munmap(unsafe.Pointer(&b[0]), uintptr(len(b)))
   239  	if errCode != 0 {
   240  		err = getErrno()
   241  	}
   242  	return err
   243  }
   244  
   245  func Mprotect(b []byte, prot int) (err error) {
   246  	errCode := libc_mprotect(unsafe.Pointer(&b[0]), uintptr(len(b)), int32(prot))
   247  	if errCode != 0 {
   248  		err = getErrno()
   249  	}
   250  	return
   251  }
   252  
   253  func Environ() []string {
   254  
   255  	// This function combines all the environment into a single allocation.
   256  	// While this optimizes for memory usage and garbage collector
   257  	// overhead, it does run the risk of potentially pinning a "large"
   258  	// allocation if a user holds onto a single environment variable or
   259  	// value.  Having each variable be its own allocation would make the
   260  	// trade-off in the other direction.
   261  
   262  	// calculate total memory required
   263  	var length uintptr
   264  	var vars int
   265  	for environ := libc_environ; *environ != nil; {
   266  		length += libc_strlen(*environ)
   267  		vars++
   268  		environ = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(environ), unsafe.Sizeof(environ)))
   269  	}
   270  
   271  	// allocate our backing slice for the strings
   272  	b := make([]byte, length)
   273  	// and the slice we're going to return
   274  	envs := make([]string, 0, vars)
   275  
   276  	// loop over the environment again, this time copying over the data to the backing slice
   277  	for environ := libc_environ; *environ != nil; {
   278  		length = libc_strlen(*environ)
   279  		// construct a Go string pointing at the libc-allocated environment variable data
   280  		var envVar string
   281  		rawEnvVar := (*struct {
   282  			ptr    unsafe.Pointer
   283  			length uintptr
   284  		})(unsafe.Pointer(&envVar))
   285  		rawEnvVar.ptr = *environ
   286  		rawEnvVar.length = length
   287  		// pull off the number of bytes we need for this environment variable
   288  		var bs []byte
   289  		bs, b = b[:length], b[length:]
   290  		// copy over the bytes to the Go heap
   291  		copy(bs, envVar)
   292  		// convert trimmed slice to string
   293  		s := *(*string)(unsafe.Pointer(&bs))
   294  		// add s to our list of environment variables
   295  		envs = append(envs, s)
   296  		// environ++
   297  		environ = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(environ), unsafe.Sizeof(environ)))
   298  	}
   299  	return envs
   300  }
   301  
   302  // BytePtrFromString returns a pointer to a NUL-terminated array of
   303  // bytes containing the text of s. If s contains a NUL byte at any
   304  // location, it returns (nil, EINVAL).
   305  func BytePtrFromString(s string) (*byte, error) {
   306  	for i := 0; i < len(s); i++ {
   307  		if s[i] == 0 {
   308  			return nil, EINVAL
   309  		}
   310  	}
   311  	return &cstring(s)[0], nil
   312  }
   313  
   314  // cstring converts a Go string to a C string.
   315  func cstring(s string) []byte {
   316  	data := make([]byte, len(s)+1)
   317  	copy(data, s)
   318  	// final byte should be zero from the initial allocation
   319  	return data
   320  }
   321  
   322  func splitSlice(p []byte) (buf *byte, len uintptr) {
   323  	slice := (*sliceHeader)(unsafe.Pointer(&p))
   324  	return slice.buf, slice.len
   325  }
   326  
   327  // These two functions are provided by the runtime.
   328  func runtimeSetenv(key, value string)
   329  func runtimeUnsetenv(key string)
   330  
   331  //export strlen
   332  func libc_strlen(ptr unsafe.Pointer) uintptr
   333  
   334  // ssize_t write(int fd, const void *buf, size_t count)
   335  //
   336  //export write
   337  func libc_write(fd int32, buf *byte, count uint) int
   338  
   339  // char *getenv(const char *name);
   340  //
   341  //export getenv
   342  func libc_getenv(name *byte) *byte
   343  
   344  // ssize_t read(int fd, void *buf, size_t count);
   345  //
   346  //export read
   347  func libc_read(fd int32, buf *byte, count uint) int
   348  
   349  // ssize_t pread(int fd, void *buf, size_t count, off_t offset);
   350  //
   351  //export pread
   352  func libc_pread(fd int32, buf *byte, count uint, offset int64) int
   353  
   354  // ssize_t pwrite(int fd, void *buf, size_t count, off_t offset);
   355  //
   356  //export pwrite
   357  func libc_pwrite(fd int32, buf *byte, count uint, offset int64) int
   358  
   359  // ssize_t lseek(int fd, off_t offset, int whence);
   360  //
   361  //export lseek
   362  func libc_lseek(fd int32, offset int64, whence int) int64
   363  
   364  // int close(int fd)
   365  //
   366  //export close
   367  func libc_close(fd int32) int32
   368  
   369  // int dup(int fd)
   370  //
   371  //export dup
   372  func libc_dup(fd int32) int32
   373  
   374  // void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
   375  //
   376  //export mmap
   377  func libc_mmap(addr unsafe.Pointer, length uintptr, prot, flags, fd int32, offset uintptr) unsafe.Pointer
   378  
   379  // int munmap(void *addr, size_t length);
   380  //
   381  //export munmap
   382  func libc_munmap(addr unsafe.Pointer, length uintptr) int32
   383  
   384  // int mprotect(void *addr, size_t len, int prot);
   385  //
   386  //export mprotect
   387  func libc_mprotect(addr unsafe.Pointer, len uintptr, prot int32) int32
   388  
   389  // int chdir(const char *pathname, mode_t mode);
   390  //
   391  //export chdir
   392  func libc_chdir(pathname *byte) int32
   393  
   394  // int chmod(const char *pathname, mode_t mode);
   395  //
   396  //export chmod
   397  func libc_chmod(pathname *byte, mode uint32) int32
   398  
   399  // int mkdir(const char *pathname, mode_t mode);
   400  //
   401  //export mkdir
   402  func libc_mkdir(pathname *byte, mode uint32) int32
   403  
   404  // int rmdir(const char *pathname);
   405  //
   406  //export rmdir
   407  func libc_rmdir(pathname *byte) int32
   408  
   409  // int rename(const char *from, *to);
   410  //
   411  //export rename
   412  func libc_rename(from, to *byte) int32
   413  
   414  // int symlink(const char *from, *to);
   415  //
   416  //export symlink
   417  func libc_symlink(from, to *byte) int32
   418  
   419  // int fsync(int fd);
   420  //
   421  //export fsync
   422  func libc_fsync(fd int32) int32
   423  
   424  // ssize_t readlink(const char *path, void *buf, size_t count);
   425  //
   426  //export readlink
   427  func libc_readlink(path *byte, buf *byte, count uint) int
   428  
   429  // int unlink(const char *pathname);
   430  //
   431  //export unlink
   432  func libc_unlink(pathname *byte) int32
   433  
   434  //go:extern environ
   435  var libc_environ *unsafe.Pointer