/* -*- mode: c; c-basic-offset: 3 -*- */ case 0: { /* clock_gettime clock_id → nanoseconds */ struct timespec ts; if (clock_gettime(cnum(a), &ts) != -1) return onum(ts.tv_sec * INT64_C(1000000000) + ts.tv_nsec, 1); return IFALSE; } case 1: { /* open path flags mode → port | #f */ if (stringp(a)) { int fd = open((const char *)a + W, cnum(b), immval(c)); if (fd != -1) return make_immediate(fd, TPORT); } return IFALSE; } case 2: { return BOOL(close(immval(a)) == 0); } case 3: { /* 3 = sopen port 0=tcp|1=udp -> False | fd */ int port = immval(a); int type = immval(b); int s; int opt = 1; /* TRUE */ char udp = (type == 1); struct sockaddr_in myaddr; myaddr.sin_family = AF_INET; myaddr.sin_port = htons(port); myaddr.sin_addr.s_addr = INADDR_ANY; s = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), (udp ? IPPROTO_UDP : 0)); if (s < 0) return IFALSE; if (type != 1) { if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) \ || bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr)) != 0 \ || listen(s, SOMAXCONN) != 0) { close(s); return IFALSE; } } else { if (bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr)) != 0) { close(s); return IFALSE; } } return make_immediate(s, TPORT); } case 5: { /* read fd len -> bvec | EOF | #f */ if (is_type(a, TPORT)) { size_t len = memend - fp; const size_t max = len > MAXOBJ ? MAXPAYL : (len - 1) * W; len = cnum(b); len = read(immval(a), fp + 1, len < max ? len : max); if (len == 0) return IEOF; if (len != (size_t)-1) return mkraw(TBVEC, len); } return IFALSE; } case 9: { /* return process variables */ return onum( a == F(0) ? errno : a == F(1) ? (uintptr_t)environ : a == F(8) ? nalloc + fp - memstart : /* total allocated objects so far */ a == F(9) ? maxheap : /* maximum heap size in a major gc */ max_heap_mb, 0); } case 18: { /* fork → #f: failed, 0: we're in child process, integer: we're in parent process */ pid_t pid = fork(); return pid != -1 ? onum(pid, 1) : IFALSE; } case 19: { /* wait _ */ pid_t pid = a != IFALSE ? cnum(a) : -1; int status; word *r = (word *)b; pid = waitpid(pid, &status, WNOHANG|WUNTRACED); /* |WCONTINUED */ if (pid == -1) return IFALSE; /* error */ if (pid == 0) return ITRUE; /* no changes, would block */ if (WIFEXITED(status)) { r[1] = F(1); r[2] = F(WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { r[1] = F(2); r[2] = F(WTERMSIG(status)); } else if (WIFSTOPPED(status)) { r[1] = F(3); r[2] = F(WSTOPSIG(status)); /*} else if (WIFCONTINUED(status)) { r[1] = F(4); r[2] = F(1); */ } else { r = (word *)IFALSE; } return (word)r; } case 21: {/* kill pid signal → bool */ return BOOL(kill(cnum(a), immval(b)) == 0); } case 24: { /* mknod path (type . mode) dev → bool */ if (stringp(a) && pairp(b)) { const char *path = (const char *)a + W; const mode_t type = cnum(G(b, 1)), mode = immval(G(b, 2)); if ((type == S_IFDIR ? mkdir(path, mode) : mknod(path, type | mode, cnum(c))) == 0) return ITRUE; } return IFALSE; } case 26: { if (a != IFALSE) { static struct termios old; tcgetattr(0, &old); old.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); old.c_oflag &= ~OPOST; old.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); old.c_cflag &= ~(CSIZE | PARENB); old.c_cflag |= CS8; return BOOL(tcsetattr(0, TCSANOW, &old) == 0); } return BOOL(tcsetattr(0, TCSANOW, &tsettings) == 0); } case 28: { /* setenv */ if (stringp(a) && (b == IFALSE || stringp(b))) { const char *name = (const char *)a + W; if ((b != IFALSE ? setenv(name, (const char *)b + W, 1) : unsetenv(name)) == 0) return ITRUE; } return IFALSE; } case 31: { /* pipe → '(read-port . write-port) | #f */ int fd[2]; if (pipe(fd) != 0) return IFALSE; return cons(make_immediate(fd[0], TPORT), make_immediate(fd[1], TPORT)); } case 32: { /* rename src dst → bool */ return BOOL(stringp(a) && stringp(b) && rename((char *)a + W, (char *)b + W) == 0); } case 33: { /* link src dst → bool */ return BOOL(stringp(a) && stringp(b) && link((char *)a + W, (char *)b + W) == 0); } case 34: { /* symlink src dst → bool */ return BOOL(stringp(a) && stringp(b) && symlink((char *)a + W, (char *)b + W) == 0); } case 35: { /* readlink path → raw-sting | #false */ if (stringp(a)) { size_t len = memend - fp; size_t max = len > MAXOBJ ? MAXPAYL + 1 : (len - 1) * W; /* the last byte is temporarily used to check, if the string fits */ len = readlink((const char *)a + W, (char *)fp + W, max); if (len != (size_t)-1 && len != max) return mkraw(TSTRING, len); } return IFALSE; } case 38: { /* stat fd|path follow → list */ if (immediatep(a) || stringp(a)) { struct stat st; int flg = b != IFALSE ? 0 : AT_SYMLINK_NOFOLLOW; if ((allocp(a) ? fstatat(AT_FDCWD, (char *)a + W, &st, flg) : fstat(immval(a), &st)) == 0) { word lst = INULL; lst = cons(onum(st.st_blocks, 1), lst); lst = cons(onum(st.st_blksize, 1), lst); lst = cons(onum(st.st_ctim.tv_sec * INT64_C(1000000000) + st.st_atim.tv_nsec, 1), lst); lst = cons(onum(st.st_mtim.tv_sec * INT64_C(1000000000) + st.st_atim.tv_nsec, 1), lst); lst = cons(onum(st.st_atim.tv_sec * INT64_C(1000000000) + st.st_atim.tv_nsec, 1), lst); lst = cons(onum(st.st_size, 1), lst); lst = cons(onum(st.st_rdev, 0), lst); lst = cons(onum(st.st_gid, 0), lst); lst = cons(onum(st.st_uid, 0), lst); lst = cons(onum(st.st_nlink, 0), lst); lst = cons(onum(st.st_mode, 0), lst); lst = cons(onum(st.st_ino, 0), lst); lst = cons(onum(st.st_dev, 1), lst); return lst; } } return INULL; } case 39: { /* chmod fd|path mode follow → bool */ if ((immediatep(a) || stringp(a)) && fixnump(b)) { mode_t mod = immval(b); int flg = c != IFALSE ? 0 : AT_SYMLINK_NOFOLLOW; if ((allocp(a) ? fchmodat(AT_FDCWD, (char *)a + W, mod, flg) : fchmod(immval(a), mod)) == 0) return ITRUE; } return IFALSE; } case 40: { /* chown fd|path (uid . gid) follow → bool */ if ((immediatep(a) || stringp(a)) && pairp(b)) { uid_t uid = cnum(G(b, 1)); gid_t gid = cnum(G(b, 2)); int flg = c != IFALSE ? 0 : AT_SYMLINK_NOFOLLOW; if ((allocp(a) ? fchownat(AT_FDCWD, (char *)a + W, uid, gid, flg) : fchown(immval(a), uid, gid)) == 0) return ITRUE; } return IFALSE; } case 42: { /* write fd data len | #f → nbytes | #f */ if (is_type(a, TPORT) && allocp(b)) { size_t len, size = payl_len(header(b)); len = c != IFALSE ? cnum(c) : size; if (len <= size) { len = write(immval(a), (const word *)b + 1, len); if (len != (size_t)-1) return onum(len, 0); } } return IFALSE; } case 43: { return do_poll(a, b, c); } case 46: { /* catch-signals (4 8 ...) _ _*/ struct sigaction sa; word *lst = (word *)a; sa.sa_handler = catch_signal; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; while((word)lst != INULL) { sigaction(immval(lst[1]), &sa, NULL); //printf("[vm: will catch %d]\n", immval(lst[1])); lst = (word *)lst[2]; } return ITRUE; }