τau / syscall /

syscall.tau

source
/Users/niconex/Documents/tau/stdlib/syscall/syscall.tau
1# syscall.tau - Low-level system call interface for Tau2# Provides a cross-platform abstraction layer for system calls3# Similar to Go's syscall package45ffi = import("ffi")67# The library is looked up next to the installed stdlib, dlopen() falls back8# to ~/.local/lib/tau and /lib/tau when the relative path doesn't exist.9lib = dlopen("libsyscall.so")1011# Every call is declared, so that a result comes back the width it really has12# rather than as a machine word to be read with int(x, 64) - and forgetting13# the 64 truncated it to an int of C, which is what a size or a millisecond14# does not fit in.15sys = ffi.Bind(lib, [16	"int64_t sys_open(const char *path, int64_t flags, int64_t mode)",17	"int64_t sys_close(int64_t fd)",18	"int64_t sys_read(int64_t fd, void *buf, int64_t count)",19	"int64_t sys_write(int64_t fd, const void *buf, int64_t count)",20	"int64_t sys_lseek(int64_t fd, int64_t offset, int64_t whence)",21	"int64_t sys_unlink(const char *path)",22	"int64_t sys_mkdir(const char *path, int64_t mode)",23	"int64_t sys_rmdir(const char *path)",24	"int64_t sys_chmod(const char *path, int64_t mode)",25	"int64_t sys_access(const char *path, int64_t mode)",26	"int64_t sys_socket(int64_t domain, int64_t type, int64_t protocol)",27	"int64_t sys_bind(int64_t sockfd, const void *addr, int64_t addrlen)",28	"int64_t sys_listen(int64_t sockfd, int64_t backlog)",29	"int64_t sys_accept(int64_t sockfd, void *addr, void *addrlen)",30	"int64_t sys_connect(int64_t sockfd, const void *addr, int64_t addrlen)",31	"int64_t sys_getsockname(int64_t sockfd, void *addr, void *addrlen)",32	"int64_t sys_send(int64_t sockfd, const void *buf, int64_t len, int64_t flags)",33	"int64_t sys_recv(int64_t sockfd, void *buf, int64_t len, int64_t flags)",34	"int64_t sys_sendto(int64_t sockfd, const void *buf, int64_t len, int64_t flags, const void *dest_addr, int64_t addrlen)",35	"int64_t sys_recvfrom(int64_t sockfd, void *buf, int64_t len, int64_t flags, void *src_addr, void *addrlen)",36	"int64_t sys_setsockopt(int64_t sockfd, int64_t level, int64_t optname, const void *optval, int64_t optlen)",37	"int64_t sys_getsockopt(int64_t sockfd, int64_t level, int64_t optname, void *optval, void *optlen)",38	"int64_t sys_shutdown(int64_t sockfd, int64_t how)",39	"uint16_t sys_htons(uint16_t hostshort)",40	"uint16_t sys_ntohs(uint16_t netshort)",41	"uint32_t sys_htonl(uint32_t hostlong)",42	"uint32_t sys_ntohl(uint32_t netlong)",43	"uint32_t sys_inet_addr(const char *cp)",44	"int64_t sys_sockaddr_in(void *buf, const char *ip, int64_t port)",45	"int64_t sys_sockaddr_in_size()",46	"int64_t sys_sockaddr_port(const void *buf)",47	"int64_t sys_sockaddr_ip(const void *buf, void *out, int64_t outlen)",48	"int64_t sys_int32(void *buf, int64_t v)",49	"int64_t sys_int32_size()",50	"int64_t sys_timeval(void *buf, int64_t ms)",51	"int64_t sys_timeval_size()",52	"int64_t sys_time_unix()",53	"int64_t sys_time_ms()",54	"int64_t sys_time_mono_ms()",55	"int64_t sys_sleep_ms(int64_t ms)",56	"int64_t sys_strerror(int64_t err, void *out, int64_t outlen)",57	"int64_t sys_errno()",58	"void sys_set_errno(int64_t err)",59	"int64_t sys_getenv(const char *name, void *out, int64_t outlen)",60	"int64_t sys_setenv(const char *name, const char *value, int64_t overwrite)",61	"int64_t sys_unsetenv(const char *name)",62	"int64_t sys_stat_size(const char *path)",63	"int64_t sys_stat_mode(const char *path)",64	"int64_t sys_stat_mtime(const char *path)",65	"int64_t sys_stat_isdir(const char *path)",66	"int64_t sys_rename(const char *from, const char *to)",67	"int64_t sys_getcwd(void *out, int64_t outlen)",68	"int64_t sys_chdir(const char *path)",69	"int64_t sys_opendir(const char *path)",70	"int64_t sys_readdir(int64_t dir, void *out, int64_t outlen)",71	"int64_t sys_closedir(int64_t dir)",72	"int64_t sys_tz_offset(int64_t t)",73	"int64_t sys_tz_name(int64_t t, void *out, int64_t outlen)",74	"int64_t sys_spawn_status(void)",75	"int64_t sys_spawn(const void *blob, int64_t bloblen, int64_t nargs, const void *in, int64_t inlen, void *out, int64_t outcap, int64_t flags)"76])7778# ========== Error Handling ==========7980Errno = fn() { sys.sys_errno() }81SetErrno = fn(err) { sys.sys_set_errno(err) }8283# Strerror returns the message of an errno value.84Strerror = fn(err) {85	buf = bytes(256)86	n = sys.sys_strerror(err, buf, 256)87	return string(slice(buf, 0, n))88}8990# Error builds an error for a failed call, with the message of the errno.91Error = fn(what) {92	err = Errno()93	return error("{what}: {Strerror(err)} (errno {err})")94}9596# ========== File Operation Constants ==========9798# open() flags - Linux/macOS values (POSIX)99O_RDONLY = 0x0000100O_WRONLY = 0x0001101O_RDWR = 0x0002102O_CREAT = 0x0040103O_EXCL = 0x0080104O_TRUNC = 0x0200105O_APPEND = 0x0400106O_NONBLOCK = 0x0800107O_SYNC = 0x1000108109# File permissions110S_IRWXU = 0x01C0 # User: rwx111S_IRUSR = 0x0100 # User: r--112S_IWUSR = 0x0080 # User: -w-113S_IXUSR = 0x0040 # User: --x114S_IRWXG = 0x0038 # Group: rwx115S_IRGRP = 0x0020 # Group: r--116S_IWGRP = 0x0010 # Group: -w-117S_IXGRP = 0x0008 # Group: --x118S_IRWXO = 0x0007 # Other: rwx119S_IROTH = 0x0004 # Other: r--120S_IWOTH = 0x0002 # Other: -w-121S_IXOTH = 0x0001 # Other: --x122123# lseek() whence124SEEK_SET = 0125SEEK_CUR = 1126SEEK_END = 2127128# access() mode129F_OK = 0 # Test for existence130X_OK = 1 # Test for execute permission131W_OK = 2 # Test for write permission132R_OK = 4 # Test for read permission133134# ========== Network Constants ==========135136# Address families137AF_INET = 2 # IPv4138AF_INET6 = 10 # IPv6139AF_UNIX = 1 # Unix domain sockets140141# Socket types142SOCK_STREAM = 1 # TCP143SOCK_DGRAM = 2 # UDP144SOCK_RAW = 3 # Raw socket145146# Protocols147IPPROTO_IP = 0148IPPROTO_TCP = 6149IPPROTO_UDP = 17150151# Socket options - level152SOL_SOCKET = 1153154# Socket options - names155SO_REUSEADDR = 2156SO_REUSEPORT = 15157SO_KEEPALIVE = 9158SO_BROADCAST = 6159SO_LINGER = 13160SO_RCVBUF = 8161SO_SNDBUF = 7162SO_RCVTIMEO = 20163SO_SNDTIMEO = 21164165# shutdown() how166SHUT_RD = 0167SHUT_WR = 1168SHUT_RDWR = 2169170# Listen backlog171SOMAXCONN = 128172173# The error numbers live in the errno module, which lists them all:174#175#	errno = import("errno")176#	if syscall.Errno() == errno.EAGAIN { ... }177178# ========== File Operations ==========179180Open = fn(path, flags, mode) {181	result = sys.sys_open(path, flags, mode)182	if result < 0 {183		return error("open failed: errno {Errno()}")184	}185	return result186}187188Close = fn(fd) {189	result = sys.sys_close(fd)190	if result < 0 {191		return error("close failed: errno {Errno()}")192	}193	return result194}195196Read = fn(fd, buf, count) {197	result = sys.sys_read(fd, buf, count)198	if result < 0 {199		return error("read failed: errno {Errno()}")200	}201	return result202}203204Write = fn(fd, buf, count) {205	result = sys.sys_write(fd, buf, count)206	if result < 0 {207		return error("write failed: errno {Errno()}")208	}209	return result210}211212Lseek = fn(fd, offset, whence) {213	result = sys.sys_lseek(fd, offset, whence)214	if result < 0 {215		return error("lseek failed: errno {Errno()}")216	}217	return result218}219220Unlink = fn(path) {221	result = sys.sys_unlink(path)222	if result < 0 {223		return error("unlink failed: errno {Errno()}")224	}225	return result226}227228Mkdir = fn(path, mode) {229	result = sys.sys_mkdir(path, mode)230	if result < 0 {231		return error("mkdir failed: errno {Errno()}")232	}233	return result234}235236Rmdir = fn(path) {237	result = sys.sys_rmdir(path)238	if result < 0 {239		return error("rmdir failed: errno {Errno()}")240	}241	return result242}243244Chmod = fn(path, mode) {245	result = sys.sys_chmod(path, mode)246	if result < 0 {247		return error("chmod failed: errno {Errno()}")248	}249	return result250}251252Access = fn(path, mode) {253	result = sys.sys_access(path, mode)254	if result < 0 {255		return error("access failed: errno {Errno()}")256	}257	return result258}259260# ========== Network Operations ==========261262Socket = fn(domain, socktype, protocol) {263	result = sys.sys_socket(domain, socktype, protocol)264	if result < 0 {265		return error("socket failed: errno {Errno()}")266	}267	return result268}269270Bind = fn(sockfd, addr, addrlen) {271	result = sys.sys_bind(sockfd, addr, addrlen)272	if result < 0 {273		return error("bind failed: errno {Errno()}")274	}275	return result276}277278Listen = fn(sockfd, backlog) {279	result = sys.sys_listen(sockfd, backlog)280	if result < 0 {281		return error("listen failed: errno {Errno()}")282	}283	return result284}285286Accept = fn(sockfd, addr, addrlen) {287	result = sys.sys_accept(sockfd, addr, addrlen)288	if result < 0 {289		return error("accept failed: errno {Errno()}")290	}291	return result292}293294Getsockname = fn(sockfd, addr, addrlen) {295	if sys.sys_getsockname(sockfd, addr, addrlen) < 0 {296		return error("getsockname failed: errno {Errno()}")297	}298	return null299}300301Connect = fn(sockfd, addr, addrlen) {302	result = sys.sys_connect(sockfd, addr, addrlen)303	if result < 0 {304		return error("connect failed: errno {Errno()}")305	}306	return result307}308309Send = fn(sockfd, buf, len, flags) {310	result = sys.sys_send(sockfd, buf, len, flags)311	if result < 0 {312		return error("send failed: errno {Errno()}")313	}314	return result315}316317Recv = fn(sockfd, buf, len, flags) {318	result = sys.sys_recv(sockfd, buf, len, flags)319	if result < 0 {320		return error("recv failed: errno {Errno()}")321	}322	return result323}324325Sendto = fn(sockfd, buf, len, flags, dest_addr, addrlen) {326	result = sys.sys_sendto(sockfd, buf, len, flags, dest_addr, addrlen)327	if result < 0 {328		return error("sendto failed: errno {Errno()}")329	}330	return result331}332333Recvfrom = fn(sockfd, buf, len, flags, src_addr, addrlen) {334	result = sys.sys_recvfrom(sockfd, buf, len, flags, src_addr, addrlen)335	if result < 0 {336		return error("recvfrom failed: errno {Errno()}")337	}338	return result339}340341Setsockopt = fn(sockfd, level, optname, optval, optlen) {342	result = sys.sys_setsockopt(sockfd, level, optname, optval, optlen)343	if result < 0 {344		return error("setsockopt failed: errno {Errno()}")345	}346	return result347}348349Getsockopt = fn(sockfd, level, optname, optval, optlen) {350	result = sys.sys_getsockopt(sockfd, level, optname, optval, optlen)351	if result < 0 {352		return error("getsockopt failed: errno {Errno()}")353	}354	return result355}356357Shutdown = fn(sockfd, how) {358	result = sys.sys_shutdown(sockfd, how)359	if result < 0 {360		return error("shutdown failed: errno {Errno()}")361	}362	return result363}364365# ========== Network Helper Functions ==========366367Htons = fn(hostshort) { sys.sys_htons(hostshort) }368Ntohs = fn(netshort) { sys.sys_ntohs(netshort) }369Htonl = fn(hostlong) { sys.sys_htonl(hostlong) }370Ntohl = fn(netlong) { sys.sys_ntohl(netlong) }371InetAddr = fn(cp) { sys.sys_inet_addr(cp) }372373# ========== Address Helpers ==========374375# SockaddrInSize is the length of a sockaddr_in.376SockaddrInSize = fn() { sys.sys_sockaddr_in_size() }377378# SockaddrIn returns a sockaddr_in filled for ip:port, ready for Bind,379# Connect and Sendto. An empty ip means "any address".380SockaddrIn = fn(ip, port) {381	buf = bytes(SockaddrInSize())382	sys.sys_sockaddr_in(buf, ip, port)383	return buf384}385386# SockaddrPort returns the port stored in a sockaddr_in.387SockaddrPort = fn(sa) { sys.sys_sockaddr_port(sa) }388389# SockaddrIP returns the dotted address stored in a sockaddr_in.390SockaddrIP = fn(sa) {391	buf = bytes(64)392	n = sys.sys_sockaddr_ip(sa, buf, 64)393	return string(slice(buf, 0, n))394}395396# ========== Small Structs ==========397398# Int32 returns the bytes of a native int32, for the calls that want a399# pointer to one.400Int32 = fn(n) {401	buf = bytes(sys.sys_int32_size())402	sys.sys_int32(buf, n)403	return buf404}405406# Timeval returns the bytes of a struct timeval of ms milliseconds, for the407# timeout options of setsockopt.408Timeval = fn(ms) {409	buf = bytes(sys.sys_timeval_size())410	sys.sys_timeval(buf, ms)411	return buf412}413414# ========== Time ==========415416# TimeUnix returns the wall clock time in seconds since the Unix epoch.417TimeUnix = fn() { sys.sys_time_unix() }418419# TimeMillis returns the wall clock time in milliseconds.420TimeMillis = fn() { sys.sys_time_ms() }421422# TimeMono returns a monotonic timestamp in milliseconds.423TimeMono = fn() { sys.sys_time_mono_ms() }424425# SleepMillis pauses the current tau routine for ms milliseconds.426SleepMillis = fn(ms) { sys.sys_sleep_ms(ms) }427428# ========== Environment ==========429430# Getenv returns the value of the variable name, or null when it isn't set.431Getenv = fn(name) {432	buf = bytes(4096)433	n = sys.sys_getenv(name, buf, 4096)434	if n < 0 {435		return null436	}437	return string(slice(buf, 0, n))438}439440# Setenv sets the variable name to value, overwriting what was there.441Setenv = fn(name, value) {442	if sys.sys_setenv(name, value, 1) < 0 {443		return Error("setenv")444	}445	return null446}447448# Unsetenv removes the variable name.449Unsetenv = fn(name) {450	if sys.sys_unsetenv(name) < 0 {451		return Error("unsetenv")452	}453	return null454}455456# ========== File Metadata ==========457458# The bits of a file mode, as returned by StatMode.459S_IFMT = 0170000460S_IFDIR = 0040000461S_IFREG = 0100000462S_IFLNK = 0120000463464# StatSize returns the size of the file at path in bytes.465StatSize = fn(path) {466	n = sys.sys_stat_size(path)467	if n < 0 {468		return Error("stat {path}")469	}470	return n471}472473# StatMode returns the mode of the file at path, permissions and type.474StatMode = fn(path) {475	n = sys.sys_stat_mode(path)476	if n < 0 {477		return Error("stat {path}")478	}479	return n480}481482# StatMtime returns when the file at path was last modified, in seconds since483# the Unix epoch.484StatMtime = fn(path) {485	n = sys.sys_stat_mtime(path)486	if n < 0 {487		return Error("stat {path}")488	}489	return n490}491492# StatIsDir reports whether path is a directory.493StatIsDir = fn(path) {494	n = sys.sys_stat_isdir(path)495	if n < 0 {496		return Error("stat {path}")497	}498	return n == 1499}500501Rename = fn(from, to) {502	if sys.sys_rename(from, to) < 0 {503		return Error("rename {from}")504	}505	return null506}507508# Getwd returns the working directory.509Getwd = fn() {510	buf = bytes(4096)511	n = sys.sys_getcwd(buf, 4096)512	if n < 0 {513		return Error("getcwd")514	}515	return string(slice(buf, 0, n))516}517518Chdir = fn(path) {519	if sys.sys_chdir(path) < 0 {520		return Error("chdir {path}")521	}522	return null523}524525# ========== Directories ==========526527# Readdirnames returns the names inside the directory at path, "." and ".."528# included, the way the system hands them over.529Readdirnames = fn(path) {530	d = sys.sys_opendir(path)531	if d == 0 {532		return Error("opendir {path}")533	}534535	names = []536	buf = bytes(4096)537	for {538		n = sys.sys_readdir(d, buf, 4096)539		if n < 0 {540			sys.sys_closedir(d)541			return names542		}543		names = append(names, string(slice(buf, 0, n)))544	}545}546547# ========== Time Zone ==========548549# TzOffset returns the seconds between local time and UTC at the instant sec,550# daylight saving included.551TzOffset = fn(sec) { sys.sys_tz_offset(sec) }552553# TzName returns the abbreviation of the local zone at the instant sec.554TzName = fn(sec) {555	buf = bytes(64)556	n = sys.sys_tz_name(sec, buf, 64)557	if n < 0 {558		return Error("tzname")559	}560	return string(slice(buf, 0, n))561}562563# ========== Processes ==========564565# Spawn runs a program and waits for it. blob holds the program and its566# arguments one after the other, each one ended by a zero byte, and nargs says567# how many there are. What the program writes on its standard output is copied568# into out, and the return value is how many bytes it wrote in all: more than569# len(out) means the rest was thrown away.570#571# input is written to the standard input of the program, or null for nothing.572# The flags are 1 to fold standard error into the output and 2 to leave both573# alone, inherited from this process.574#575# The exit status is read with SpawnStatus after the call. See the exec module576# for the usual way to reach all this.577Spawn = fn(blob, nargs, input, out, flags) {578	inlen = if input == null { 0 } else { len(input) }579	outcap = if out == null { 0 } else { len(out) }580581	n = sys.sys_spawn(blob, len(blob), nargs, input, inlen, out, outcap, flags)582	if n < 0 {583		return Error("spawn")584	}585	return n586}587588# SpawnStatus is the exit status of the last Spawn: what the program passed to589# exit, or 128 plus the signal that killed it, or 127 when it wasn't found.590SpawnStatus = fn() { sys.sys_spawn_status() }