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