jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe@344: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: jbe/bsw@0: #define EXTOS_MAX_ERRLEN 80 jbe/bsw@0: #define EXTOS_EXEC_MAX_ARGS 64 jbe/bsw@0: jbe@372: #define EXTOS_STRERROR_R_MSG "Error detail unavailable due to noncompliant strerror_r() implementation" jbe@372: jbe/bsw@0: static lua_Number extos_monotonic_start_time; jbe/bsw@0: jbe/bsw@0: static int extos_pfilter(lua_State *L) { jbe/bsw@0: int i, result, exit_status, status_pipe_len; jbe/bsw@0: const char *in_buf; jbe/bsw@0: size_t in_len; jbe/bsw@0: size_t in_pos = 0; jbe/bsw@0: const char *filename; jbe/bsw@0: const char *args[EXTOS_EXEC_MAX_ARGS+2]; jbe/bsw@0: int pipe_status[2]; jbe/bsw@0: int pipe_in[2]; jbe/bsw@0: int pipe_out[2]; jbe/bsw@0: int pipe_err[2]; jbe/bsw@0: pid_t child; jbe/bsw@0: char status_buf[1]; jbe/bsw@0: char *out_buf = NULL; jbe/bsw@0: size_t out_len = 1024; jbe/bsw@0: size_t out_pos = 0; jbe/bsw@0: char *err_buf = NULL; jbe/bsw@0: size_t err_len = 1024; jbe/bsw@0: size_t err_pos = 0; jbe/bsw@0: void *old_sigpipe_action; jbe/bsw@0: struct pollfd fds[3]; jbe/bsw@0: int in_closed = 0; jbe/bsw@0: int out_closed = 0; jbe/bsw@0: int err_closed = 0; jbe/bsw@0: void *newptr; jbe@372: char errmsg[EXTOS_MAX_ERRLEN+1] = EXTOS_STRERROR_R_MSG; jbe/bsw@0: in_buf = luaL_optlstring(L, 1, "", &in_len); jbe/bsw@0: filename = luaL_checkstring(L, 2); jbe/bsw@0: args[0] = filename; jbe/bsw@0: for (i = 0; i < EXTOS_EXEC_MAX_ARGS; i++) { jbe/bsw@0: if (lua_isnoneornil(L, 3+i)) break; jbe/bsw@0: else args[i+1] = luaL_checkstring(L, 3+i); jbe/bsw@0: } jbe/bsw@0: if (!lua_isnoneornil(L, 3+i)) { jbe/bsw@0: return luaL_error(L, "Too many arguments for pfilter call."); jbe/bsw@0: } jbe/bsw@0: args[i+1] = 0; jbe/bsw@0: // status pipe for internal communication jbe/bsw@0: if (pipe(pipe_status) < 0) { jbe/bsw@0: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe/bsw@0: goto extos_pfilter_error_A0; jbe/bsw@0: } jbe/bsw@0: // stdin jbe/bsw@0: if (pipe(pipe_in) < 0) { jbe/bsw@0: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe/bsw@0: goto extos_pfilter_error_A1; jbe/bsw@0: } jbe/bsw@0: if (in_len) { jbe/bsw@0: do result = fcntl(pipe_in[1], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR); jbe/bsw@0: } else { jbe/bsw@0: do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: in_closed = 1; jbe/bsw@0: } jbe/bsw@0: if (result < 0) { jbe/bsw@0: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe/bsw@0: goto extos_pfilter_error_A2; jbe/bsw@0: } jbe/bsw@0: // stdout jbe/bsw@0: if (pipe(pipe_out) < 0) { jbe/bsw@0: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe/bsw@0: goto extos_pfilter_error_A2; jbe/bsw@0: } jbe/bsw@0: do result = fcntl(pipe_out[0], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result < 0) { jbe/bsw@0: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe/bsw@0: goto extos_pfilter_error_A3; jbe/bsw@0: } jbe/bsw@0: // stderr jbe/bsw@0: if (pipe(pipe_err) < 0) { jbe/bsw@0: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe/bsw@0: goto extos_pfilter_error_A3; jbe/bsw@0: } jbe/bsw@0: do result = fcntl(pipe_err[0], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result < 0) { jbe/bsw@0: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe/bsw@0: goto extos_pfilter_error_A4; jbe/bsw@0: } jbe/bsw@0: // fork jbe/bsw@0: child = fork(); jbe/bsw@0: if (child < 0) { jbe/bsw@0: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe/bsw@0: goto extos_pfilter_error_A4; jbe/bsw@0: } jbe/bsw@0: // skip error handling jbe/bsw@0: goto extos_pfilter_success_A; jbe/bsw@0: // error handling jbe/bsw@0: extos_pfilter_error_A4: jbe/bsw@0: do result = close(pipe_err[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: do result = close(pipe_err[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: extos_pfilter_error_A3: jbe/bsw@0: do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: do result = close(pipe_out[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: extos_pfilter_error_A2: jbe/bsw@0: do result = close(pipe_in[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: extos_pfilter_error_A1: jbe/bsw@0: do result = close(pipe_status[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: do result = close(pipe_status[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: extos_pfilter_error_A0: jbe/bsw@0: return luaL_error(L, "Unexpected error in pfilter: %s", errmsg); jbe/bsw@0: // end of error handling jbe/bsw@0: extos_pfilter_success_A: jbe/bsw@0: if (child) { // parent jbe/bsw@0: old_sigpipe_action = signal(SIGPIPE, SIG_IGN); jbe/bsw@0: do result = close(pipe_status[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result < 0) goto extos_pfilter_error_B; jbe/bsw@0: do result = close(pipe_in[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result < 0) goto extos_pfilter_error_B; jbe/bsw@0: do result = close(pipe_out[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result < 0) goto extos_pfilter_error_B; jbe/bsw@0: do result = close(pipe_err[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result < 0) goto extos_pfilter_error_B; jbe/bsw@0: out_buf = malloc(out_len * sizeof(char)); jbe/bsw@0: if (!out_buf) goto extos_pfilter_error_B; jbe/bsw@0: err_buf = malloc(err_len * sizeof(char)); jbe/bsw@0: if (!err_buf) goto extos_pfilter_error_B; jbe/bsw@0: while (!in_closed || !out_closed || !err_closed) { jbe/bsw@0: i = 0; jbe/bsw@0: if (!in_closed) { jbe/bsw@0: fds[i].fd = pipe_in[1]; jbe/bsw@0: fds[i].events = POLLOUT; jbe/bsw@0: i++; jbe/bsw@0: } jbe/bsw@0: if (!out_closed) { jbe/bsw@0: fds[i].fd = pipe_out[0]; jbe/bsw@0: fds[i].events = POLLIN; jbe/bsw@0: i++; jbe/bsw@0: } jbe/bsw@0: if (!err_closed) { jbe/bsw@0: fds[i].fd = pipe_err[0]; jbe/bsw@0: fds[i].events = POLLIN; jbe/bsw@0: i++; jbe/bsw@0: } jbe/bsw@0: do result = poll(fds, i, -1); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result < 0) goto extos_pfilter_error_B; jbe/bsw@0: if (!in_closed) { jbe/bsw@0: do result = write(pipe_in[1], in_buf+in_pos, in_len-in_pos); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result < 0) { jbe/bsw@0: if (errno == EPIPE) { jbe/bsw@0: do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: in_closed = 1; jbe/bsw@0: } else if (errno != EAGAIN) { jbe/bsw@0: goto extos_pfilter_error_B; jbe/bsw@0: } jbe/bsw@0: } else { jbe/bsw@0: in_pos += result; jbe/bsw@0: if (in_pos == in_len) { jbe/bsw@0: do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: in_closed = 1; jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: if (!out_closed) { jbe/bsw@0: do result = read(pipe_out[0], out_buf+out_pos, out_len-out_pos); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result < 0) { jbe/bsw@0: if (errno != EAGAIN) goto extos_pfilter_error_B; jbe/bsw@0: } else if (result == 0) { jbe/bsw@0: do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: out_closed = 1; jbe/bsw@0: } else { jbe/bsw@0: out_pos += result; jbe/bsw@0: if (out_pos == out_len) { jbe/bsw@0: out_len *= 2; jbe/bsw@0: newptr = realloc(out_buf, out_len * sizeof(char)); jbe/bsw@0: if (!newptr) goto extos_pfilter_error_B; jbe/bsw@0: out_buf = newptr; jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: if (!err_closed) { jbe/bsw@0: do result = read(pipe_err[0], err_buf+err_pos, err_len-err_pos); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result < 0) { jbe/bsw@0: if (errno != EAGAIN) goto extos_pfilter_error_B; jbe/bsw@0: } else if (result == 0) { jbe/bsw@0: do result = close(pipe_err[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: err_closed = 1; jbe/bsw@0: } else { jbe/bsw@0: err_pos += result; jbe/bsw@0: if (err_pos == err_len) { jbe/bsw@0: err_len *= 2; jbe/bsw@0: newptr = realloc(err_buf, err_len * sizeof(char)); jbe/bsw@0: if (!newptr) goto extos_pfilter_error_B; jbe/bsw@0: err_buf = newptr; jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: lua_pushlstring(L, out_buf, out_pos); jbe/bsw@0: free(out_buf); jbe/bsw@0: out_buf = NULL; jbe/bsw@0: lua_pushlstring(L, err_buf, err_pos); jbe/bsw@0: free(err_buf); jbe/bsw@0: err_buf = NULL; jbe/bsw@0: do result = waitpid(child, &exit_status, 0); while (result < 0 && errno == EINTR); jbe/bsw@0: child = 0; jbe/bsw@0: if (result < 0) goto extos_pfilter_error_B; jbe/bsw@0: do status_pipe_len = read(pipe_status[0], status_buf, 1); while (status_pipe_len < 0 && errno == EINTR); jbe/bsw@0: if (status_pipe_len < 0) goto extos_pfilter_error_B; jbe/bsw@0: do result = close(pipe_status[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: signal(SIGPIPE, old_sigpipe_action); jbe/bsw@0: if (status_pipe_len == 0) { jbe/bsw@0: if (WIFEXITED(exit_status)) lua_pushinteger(L, WEXITSTATUS(exit_status)); jbe/bsw@0: else lua_pushinteger(L, -WTERMSIG(exit_status)); jbe/bsw@0: return 3; jbe/bsw@0: } else if (status_buf[0] == 0) { jbe/bsw@0: return luaL_error(L, "Error in pfilter while reopening standard file descriptors in child process."); jbe/bsw@0: } else { jbe/bsw@0: strerror_r(status_buf[0], errmsg, EXTOS_MAX_ERRLEN+1); jbe/bsw@0: lua_pushnil(L); jbe/bsw@0: lua_pushfstring(L, "Could not execute \"%s\": %s", filename, errmsg); jbe/bsw@0: return 2; jbe/bsw@0: } jbe/bsw@0: extos_pfilter_error_B: jbe/bsw@0: signal(SIGPIPE, old_sigpipe_action); jbe/bsw@0: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe/bsw@0: if (out_buf) free(out_buf); jbe/bsw@0: if (err_buf) free(err_buf); jbe/bsw@0: if (!in_closed) { jbe/bsw@0: do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: } jbe/bsw@0: if (!out_closed) { jbe/bsw@0: do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: } jbe/bsw@0: if (!err_closed) { jbe/bsw@0: do result = close(pipe_err[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: } jbe/bsw@0: if (child) do result = waitpid(child, &exit_status, 0); while (result < 0 && errno == EINTR); jbe/bsw@0: return luaL_error(L, "Unexpected error in pfilter: %s", errmsg); jbe/bsw@0: } else { // child jbe/bsw@0: do result = close(pipe_status[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: do result = close(0); while (result < 0 && errno == EINTR); jbe/bsw@0: do result = close(1); while (result < 0 && errno == EINTR); jbe/bsw@0: do result = close(2); while (result < 0 && errno == EINTR); jbe/bsw@0: do result = dup(pipe_in[0]); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result != 0) goto extos_pfilter_error_fd_remapping; jbe/bsw@0: do result = dup(pipe_out[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result != 1) goto extos_pfilter_error_fd_remapping; jbe/bsw@0: do result = dup(pipe_err[1]); while (result < 0 && errno == EINTR); jbe/bsw@0: if (result != 2) goto extos_pfilter_error_fd_remapping; jbe@550: execvp(filename, (char *const *)args); // coercion to suppress compiler warning jbe/bsw@0: status_buf[0] = errno; jbe/bsw@0: do result = write(pipe_status[1], status_buf, 1); while (result < 0 && errno == EINTR); jbe/bsw@0: _exit(0); jbe/bsw@0: extos_pfilter_error_fd_remapping: jbe/bsw@0: status_buf[0] = 0; jbe/bsw@0: do result = write(pipe_status[1], status_buf, 1); while (result < 0 && errno == EINTR); jbe/bsw@0: _exit(0); jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: jbe/bsw@0: static int extos_listdir(lua_State *L) { jbe/bsw@0: DIR *dir; jbe/bsw@0: int i = 1; jbe/bsw@0: struct dirent entry_buffer; jbe/bsw@0: struct dirent *entry; jbe/bsw@0: dir = opendir(luaL_checkstring(L, 1)); jbe/bsw@0: if (!dir) { jbe/bsw@0: lua_pushnil(L); jbe/bsw@0: lua_pushliteral(L, "Could not list directory."); jbe/bsw@0: return 2; jbe/bsw@0: } jbe/bsw@0: lua_settop(L, 0); jbe/bsw@0: lua_newtable(L); // 1 jbe/bsw@0: while (1) { jbe/bsw@0: readdir_r(dir, &entry_buffer, &entry); jbe/bsw@0: if (!entry) break; jbe/bsw@0: // Linux doesn't have d_namlen jbe/bsw@0: //lua_pushlstring(L, entry->d_name, entry->d_namlen); jbe/bsw@0: lua_pushstring(L, entry->d_name); jbe/bsw@0: lua_rawseti(L, 1, i++); jbe/bsw@0: } jbe/bsw@0: closedir(dir); jbe/bsw@0: return 1; jbe/bsw@0: } jbe/bsw@0: jbe@351: #define EXTOS_STAT_FOLLOW -1 jbe@351: #define EXTOS_STAT_NOFOLLOW -2 jbe@351: jbe@351: static int extos_stat_impl(lua_State *L, int fd) { jbe@344: struct stat sb; jbe@351: if (fd < 0) { jbe@351: const char *filename; jbe@351: filename = luaL_checkstring(L, 1); jbe@351: if (fd == EXTOS_STAT_FOLLOW ? stat(filename, &sb) : lstat(filename, &sb)) { jbe@372: char errmsg[EXTOS_MAX_ERRLEN+1] = EXTOS_STRERROR_R_MSG; jbe@351: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe@351: if (errno == ENOENT) lua_pushboolean(L, 0); jbe@351: else lua_pushnil(L); jbe@351: lua_pushfstring(L, "Could not get file stats for \"%s\": %s", filename, errmsg); jbe@351: return 2; jbe@351: } jbe@351: } else { jbe@351: if (fstat(fd, &sb)) { jbe@372: char errmsg[EXTOS_MAX_ERRLEN+1] = EXTOS_STRERROR_R_MSG; jbe@351: strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); jbe@351: lua_pushnil(L); jbe@351: lua_pushfstring(L, "Could not get file stats for open file: %s", errmsg); jbe@351: return 2; jbe@351: } jbe@344: } jbe@344: lua_createtable(L, 0, 19); jbe@344: lua_pushinteger(L, sb.st_dev); jbe@344: lua_setfield(L, -2, "dev"); jbe@344: lua_pushinteger(L, sb.st_ino); jbe@344: lua_setfield(L, -2, "ino"); jbe@344: lua_pushinteger(L, sb.st_nlink); jbe@344: lua_setfield(L, -2, "nlink"); jbe@344: lua_pushinteger(L, sb.st_atime); jbe@344: lua_setfield(L, -2, "atime"); jbe@344: lua_pushinteger(L, sb.st_mtime); jbe@344: lua_setfield(L, -2, "mtime"); jbe@344: lua_pushinteger(L, sb.st_ctime); jbe@344: lua_setfield(L, -2, "ctime"); jbe@344: lua_pushinteger(L, sb.st_size); jbe@344: lua_setfield(L, -2, "size"); jbe@344: lua_pushinteger(L, sb.st_blksize); jbe@344: lua_setfield(L, -2, "blksize"); jbe@344: lua_pushinteger(L, sb.st_blocks); jbe@344: lua_setfield(L, -2, "blocks"); jbe@344: lua_pushinteger(L, sb.st_uid); jbe@344: lua_setfield(L, -2, "uid"); jbe@344: lua_pushinteger(L, sb.st_gid); jbe@344: lua_setfield(L, -2, "gid"); jbe@344: lua_pushinteger(L, sb.st_mode); jbe@344: lua_setfield(L, -2, "mode"); jbe@344: lua_pushboolean(L, S_ISBLK(sb.st_mode)); jbe@344: lua_setfield(L, -2, "isblk"); jbe@344: lua_pushboolean(L, S_ISCHR(sb.st_mode)); jbe@344: lua_setfield(L, -2, "ischr"); jbe@344: lua_pushboolean(L, S_ISDIR(sb.st_mode)); jbe@344: lua_setfield(L, -2, "isdir"); jbe@344: lua_pushboolean(L, S_ISFIFO(sb.st_mode)); jbe@344: lua_setfield(L, -2, "isfifo"); jbe@344: lua_pushboolean(L, S_ISLNK(sb.st_mode)); jbe@344: lua_setfield(L, -2, "islnk"); jbe@344: lua_pushboolean(L, S_ISREG(sb.st_mode)); jbe@344: lua_setfield(L, -2, "isreg"); jbe@344: lua_pushboolean(L, S_ISSOCK(sb.st_mode)); jbe@344: lua_setfield(L, -2, "issock"); jbe@344: return 1; jbe@344: } jbe@344: jbe@351: static int extos_stat(lua_State *L) { jbe@351: return extos_stat_impl(L, EXTOS_STAT_FOLLOW); jbe@351: } jbe@351: jbe@351: static int extos_lstat(lua_State *L) { jbe@351: return extos_stat_impl(L, EXTOS_STAT_NOFOLLOW); jbe@351: } jbe@351: jbe@351: static int extos_fstat(lua_State *L) { jbe@351: luaL_Stream *stream; jbe@351: stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); jbe@351: if (!stream->closef) luaL_error(L, "attempt to use a closed file"); jbe@351: return extos_stat_impl(L, fileno(stream->f)); jbe@351: } jbe@351: jbe/bsw@0: static int extos_crypt(lua_State *L) { jbe@343: const char *key; jbe@343: const char *salt; jbe/bsw@0: char *result; jbe/bsw@0: key = luaL_checkstring(L, 1); jbe/bsw@0: salt = luaL_checkstring(L, 2); jbe/bsw@0: result = crypt(key, salt); // TODO: Call not thread safe jbe/bsw@0: if (result) lua_pushstring(L, result); jbe/bsw@0: else lua_pushnil(L); jbe/bsw@0: return 1; jbe/bsw@0: } jbe/bsw@0: jbe/bsw@0: static int extos_hires_time(lua_State *L) { jbe/bsw@0: struct timespec tp; jbe/bsw@0: if (clock_gettime(CLOCK_REALTIME, &tp)) { jbe/bsw@0: return luaL_error(L, "Could not access CLOCK_REALTIME."); jbe/bsw@0: } jbe@343: lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9); jbe/bsw@0: return 1; jbe/bsw@0: } jbe/bsw@0: jbe/bsw@0: // returns time in seconds since loading the library jbe/bsw@0: static int extos_monotonic_hires_time(lua_State *L) { jbe/bsw@0: struct timespec tp; jbe/bsw@0: if (clock_gettime(CLOCK_MONOTONIC, &tp)) { jbe/bsw@0: return luaL_error(L, "Could not access CLOCK_MONOTONIC."); jbe/bsw@0: } jbe/bsw@0: lua_pushnumber(L, jbe@343: tp.tv_sec + tp.tv_nsec / 1.0e9 - extos_monotonic_start_time jbe/bsw@0: ); jbe/bsw@0: return 1; jbe/bsw@0: } jbe/bsw@0: jbe@64: static const struct luaL_Reg extos_module_functions[] = { jbe@64: {"pfilter", extos_pfilter}, jbe@64: {"listdir", extos_listdir}, jbe@344: {"stat", extos_stat}, jbe@351: {"lstat", extos_lstat}, jbe@351: {"fstat", extos_fstat}, jbe@64: {"crypt", extos_crypt}, jbe@64: {"hires_time", extos_hires_time}, jbe@64: {"monotonic_hires_time", extos_monotonic_hires_time}, jbe@64: {NULL, NULL} jbe@64: }; jbe@64: jbe/bsw@0: int luaopen_extos(lua_State *L) { jbe/bsw@0: { jbe/bsw@0: struct timespec tp; jbe/bsw@0: if (clock_gettime(CLOCK_MONOTONIC, &tp)) { jbe/bsw@0: return luaL_error(L, "Could not access monotonic hires time."); jbe/bsw@0: } jbe@343: extos_monotonic_start_time = tp.tv_sec + tp.tv_nsec / 1.0e9; jbe/bsw@0: } jbe@64: #if LUA_VERSION_NUM >= 502 jbe@64: lua_newtable(L); jbe@64: luaL_setfuncs(L, extos_module_functions, 0); jbe@64: #else jbe@70: luaL_register(L, lua_tostring(L, 1), extos_module_functions); jbe@64: #endif jbe@64: return 1; jbe/bsw@0: }