| rev | line source | 
| jbe/bsw@0 | 1 #include <lua.h> | 
| jbe/bsw@0 | 2 #include <lauxlib.h> | 
| jbe/bsw@0 | 3 #include <dirent.h> | 
| jbe/bsw@0 | 4 #include <time.h> | 
| jbe/bsw@0 | 5 #include <unistd.h> | 
| jbe/bsw@0 | 6 #include <sys/types.h> | 
| jbe@344 | 7 #include <sys/stat.h> | 
| jbe/bsw@0 | 8 #include <sys/wait.h> | 
| jbe/bsw@0 | 9 #include <signal.h> | 
| jbe/bsw@0 | 10 #include <errno.h> | 
| jbe/bsw@0 | 11 #include <stdio.h> | 
| jbe/bsw@0 | 12 #include <string.h> | 
| jbe/bsw@0 | 13 #include <fcntl.h> | 
| jbe/bsw@0 | 14 #include <poll.h> | 
| jbe/bsw@0 | 15 #include <stdlib.h> | 
| jbe/bsw@0 | 16 | 
| jbe/bsw@0 | 17 #define EXTOS_MAX_ERRLEN 80 | 
| jbe/bsw@0 | 18 #define EXTOS_EXEC_MAX_ARGS 64 | 
| jbe/bsw@0 | 19 | 
| jbe/bsw@0 | 20 static lua_Number extos_monotonic_start_time; | 
| jbe/bsw@0 | 21 | 
| jbe/bsw@0 | 22 static int extos_pfilter(lua_State *L) { | 
| jbe/bsw@0 | 23   int i, result, exit_status, status_pipe_len; | 
| jbe/bsw@0 | 24   const char *in_buf; | 
| jbe/bsw@0 | 25   size_t in_len; | 
| jbe/bsw@0 | 26   size_t in_pos = 0; | 
| jbe/bsw@0 | 27   const char *filename; | 
| jbe/bsw@0 | 28   const char *args[EXTOS_EXEC_MAX_ARGS+2]; | 
| jbe/bsw@0 | 29   int pipe_status[2]; | 
| jbe/bsw@0 | 30   int pipe_in[2]; | 
| jbe/bsw@0 | 31   int pipe_out[2]; | 
| jbe/bsw@0 | 32   int pipe_err[2]; | 
| jbe/bsw@0 | 33   pid_t child; | 
| jbe/bsw@0 | 34   char status_buf[1]; | 
| jbe/bsw@0 | 35   char *out_buf = NULL; | 
| jbe/bsw@0 | 36   size_t out_len = 1024; | 
| jbe/bsw@0 | 37   size_t out_pos = 0; | 
| jbe/bsw@0 | 38   char *err_buf = NULL; | 
| jbe/bsw@0 | 39   size_t err_len = 1024; | 
| jbe/bsw@0 | 40   size_t err_pos = 0; | 
| jbe/bsw@0 | 41   void *old_sigpipe_action; | 
| jbe/bsw@0 | 42   struct pollfd fds[3]; | 
| jbe/bsw@0 | 43   int in_closed = 0; | 
| jbe/bsw@0 | 44   int out_closed = 0; | 
| jbe/bsw@0 | 45   int err_closed = 0; | 
| jbe/bsw@0 | 46   void *newptr; | 
| jbe/bsw@0 | 47   char errmsg[EXTOS_MAX_ERRLEN+1]; | 
| jbe/bsw@0 | 48   in_buf = luaL_optlstring(L, 1, "", &in_len); | 
| jbe/bsw@0 | 49   filename = luaL_checkstring(L, 2); | 
| jbe/bsw@0 | 50   args[0] = filename; | 
| jbe/bsw@0 | 51   for (i = 0; i < EXTOS_EXEC_MAX_ARGS; i++) { | 
| jbe/bsw@0 | 52     if (lua_isnoneornil(L, 3+i)) break; | 
| jbe/bsw@0 | 53     else args[i+1] = luaL_checkstring(L, 3+i); | 
| jbe/bsw@0 | 54   } | 
| jbe/bsw@0 | 55   if (!lua_isnoneornil(L, 3+i)) { | 
| jbe/bsw@0 | 56     return luaL_error(L, "Too many arguments for pfilter call."); | 
| jbe/bsw@0 | 57   } | 
| jbe/bsw@0 | 58   args[i+1] = 0; | 
| jbe/bsw@0 | 59   // status pipe for internal communication | 
| jbe/bsw@0 | 60   if (pipe(pipe_status) < 0) { | 
| jbe/bsw@0 | 61     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe/bsw@0 | 62     goto extos_pfilter_error_A0; | 
| jbe/bsw@0 | 63   } | 
| jbe/bsw@0 | 64   // stdin | 
| jbe/bsw@0 | 65   if (pipe(pipe_in) < 0) { | 
| jbe/bsw@0 | 66     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe/bsw@0 | 67     goto extos_pfilter_error_A1; | 
| jbe/bsw@0 | 68   } | 
| jbe/bsw@0 | 69   if (in_len) { | 
| jbe/bsw@0 | 70     do result = fcntl(pipe_in[1], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 71   } else { | 
| jbe/bsw@0 | 72     do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 73     in_closed = 1; | 
| jbe/bsw@0 | 74   } | 
| jbe/bsw@0 | 75   if (result < 0) { | 
| jbe/bsw@0 | 76     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe/bsw@0 | 77     goto extos_pfilter_error_A2; | 
| jbe/bsw@0 | 78   } | 
| jbe/bsw@0 | 79   // stdout | 
| jbe/bsw@0 | 80   if (pipe(pipe_out) < 0) { | 
| jbe/bsw@0 | 81     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe/bsw@0 | 82     goto extos_pfilter_error_A2; | 
| jbe/bsw@0 | 83   } | 
| jbe/bsw@0 | 84   do result = fcntl(pipe_out[0], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 85   if (result < 0) { | 
| jbe/bsw@0 | 86     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe/bsw@0 | 87     goto extos_pfilter_error_A3; | 
| jbe/bsw@0 | 88   } | 
| jbe/bsw@0 | 89   // stderr | 
| jbe/bsw@0 | 90   if (pipe(pipe_err) < 0) { | 
| jbe/bsw@0 | 91     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe/bsw@0 | 92     goto extos_pfilter_error_A3; | 
| jbe/bsw@0 | 93   } | 
| jbe/bsw@0 | 94   do result = fcntl(pipe_err[0], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 95   if (result < 0) { | 
| jbe/bsw@0 | 96     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe/bsw@0 | 97     goto extos_pfilter_error_A4; | 
| jbe/bsw@0 | 98   } | 
| jbe/bsw@0 | 99   // fork | 
| jbe/bsw@0 | 100   child = fork(); | 
| jbe/bsw@0 | 101   if (child < 0) { | 
| jbe/bsw@0 | 102     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe/bsw@0 | 103     goto extos_pfilter_error_A4; | 
| jbe/bsw@0 | 104   } | 
| jbe/bsw@0 | 105   // skip error handling | 
| jbe/bsw@0 | 106   goto extos_pfilter_success_A; | 
| jbe/bsw@0 | 107   // error handling | 
| jbe/bsw@0 | 108   extos_pfilter_error_A4: | 
| jbe/bsw@0 | 109   do result = close(pipe_err[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 110   do result = close(pipe_err[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 111   extos_pfilter_error_A3: | 
| jbe/bsw@0 | 112   do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 113   do result = close(pipe_out[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 114   extos_pfilter_error_A2: | 
| jbe/bsw@0 | 115   do result = close(pipe_in[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 116   do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 117   extos_pfilter_error_A1: | 
| jbe/bsw@0 | 118   do result = close(pipe_status[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 119   do result = close(pipe_status[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 120   extos_pfilter_error_A0: | 
| jbe/bsw@0 | 121   return luaL_error(L, "Unexpected error in pfilter: %s", errmsg); | 
| jbe/bsw@0 | 122   // end of error handling | 
| jbe/bsw@0 | 123   extos_pfilter_success_A: | 
| jbe/bsw@0 | 124   if (child) {  // parent | 
| jbe/bsw@0 | 125     old_sigpipe_action = signal(SIGPIPE, SIG_IGN); | 
| jbe/bsw@0 | 126     do result = close(pipe_status[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 127     if (result < 0) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 128     do result = close(pipe_in[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 129     if (result < 0) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 130     do result = close(pipe_out[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 131     if (result < 0) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 132     do result = close(pipe_err[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 133     if (result < 0) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 134     out_buf = malloc(out_len * sizeof(char)); | 
| jbe/bsw@0 | 135     if (!out_buf) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 136     err_buf = malloc(err_len * sizeof(char)); | 
| jbe/bsw@0 | 137     if (!err_buf) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 138     while (!in_closed || !out_closed || !err_closed) { | 
| jbe/bsw@0 | 139       i = 0; | 
| jbe/bsw@0 | 140       if (!in_closed) { | 
| jbe/bsw@0 | 141         fds[i].fd = pipe_in[1]; | 
| jbe/bsw@0 | 142         fds[i].events = POLLOUT; | 
| jbe/bsw@0 | 143         i++; | 
| jbe/bsw@0 | 144       } | 
| jbe/bsw@0 | 145       if (!out_closed) { | 
| jbe/bsw@0 | 146         fds[i].fd = pipe_out[0]; | 
| jbe/bsw@0 | 147         fds[i].events = POLLIN; | 
| jbe/bsw@0 | 148         i++; | 
| jbe/bsw@0 | 149       } | 
| jbe/bsw@0 | 150       if (!err_closed) { | 
| jbe/bsw@0 | 151         fds[i].fd = pipe_err[0]; | 
| jbe/bsw@0 | 152         fds[i].events = POLLIN; | 
| jbe/bsw@0 | 153         i++; | 
| jbe/bsw@0 | 154       } | 
| jbe/bsw@0 | 155       do result = poll(fds, i, -1); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 156       if (result < 0) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 157       if (!in_closed) { | 
| jbe/bsw@0 | 158         do result = write(pipe_in[1], in_buf+in_pos, in_len-in_pos); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 159         if (result < 0) { | 
| jbe/bsw@0 | 160           if (errno == EPIPE) { | 
| jbe/bsw@0 | 161             do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 162             in_closed = 1; | 
| jbe/bsw@0 | 163           } else if (errno != EAGAIN) { | 
| jbe/bsw@0 | 164             goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 165           } | 
| jbe/bsw@0 | 166         } else { | 
| jbe/bsw@0 | 167           in_pos += result; | 
| jbe/bsw@0 | 168           if (in_pos == in_len) { | 
| jbe/bsw@0 | 169             do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 170             in_closed = 1; | 
| jbe/bsw@0 | 171           } | 
| jbe/bsw@0 | 172         } | 
| jbe/bsw@0 | 173       } | 
| jbe/bsw@0 | 174       if (!out_closed) { | 
| jbe/bsw@0 | 175         do result = read(pipe_out[0], out_buf+out_pos, out_len-out_pos); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 176         if (result < 0) { | 
| jbe/bsw@0 | 177           if (errno != EAGAIN) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 178         } else if (result == 0) { | 
| jbe/bsw@0 | 179           do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 180           out_closed = 1; | 
| jbe/bsw@0 | 181         } else { | 
| jbe/bsw@0 | 182           out_pos += result; | 
| jbe/bsw@0 | 183           if (out_pos == out_len) { | 
| jbe/bsw@0 | 184             out_len *= 2; | 
| jbe/bsw@0 | 185             newptr = realloc(out_buf, out_len * sizeof(char)); | 
| jbe/bsw@0 | 186             if (!newptr) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 187             out_buf = newptr; | 
| jbe/bsw@0 | 188           } | 
| jbe/bsw@0 | 189         } | 
| jbe/bsw@0 | 190       } | 
| jbe/bsw@0 | 191       if (!err_closed) { | 
| jbe/bsw@0 | 192         do result = read(pipe_err[0], err_buf+err_pos, err_len-err_pos); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 193         if (result < 0) { | 
| jbe/bsw@0 | 194           if (errno != EAGAIN) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 195         } else if (result == 0) { | 
| jbe/bsw@0 | 196           do result = close(pipe_err[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 197           err_closed = 1; | 
| jbe/bsw@0 | 198         } else { | 
| jbe/bsw@0 | 199           err_pos += result; | 
| jbe/bsw@0 | 200           if (err_pos == err_len) { | 
| jbe/bsw@0 | 201             err_len *= 2; | 
| jbe/bsw@0 | 202             newptr = realloc(err_buf, err_len * sizeof(char)); | 
| jbe/bsw@0 | 203             if (!newptr) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 204             err_buf = newptr; | 
| jbe/bsw@0 | 205           } | 
| jbe/bsw@0 | 206         } | 
| jbe/bsw@0 | 207       } | 
| jbe/bsw@0 | 208     } | 
| jbe/bsw@0 | 209     lua_pushlstring(L, out_buf, out_pos); | 
| jbe/bsw@0 | 210     free(out_buf); | 
| jbe/bsw@0 | 211     out_buf = NULL; | 
| jbe/bsw@0 | 212     lua_pushlstring(L, err_buf, err_pos); | 
| jbe/bsw@0 | 213     free(err_buf); | 
| jbe/bsw@0 | 214     err_buf = NULL; | 
| jbe/bsw@0 | 215     do result = waitpid(child, &exit_status, 0); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 216     child = 0; | 
| jbe/bsw@0 | 217     if (result < 0) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 218     do status_pipe_len = read(pipe_status[0], status_buf, 1); while (status_pipe_len < 0 && errno == EINTR); | 
| jbe/bsw@0 | 219     if (status_pipe_len < 0) goto extos_pfilter_error_B; | 
| jbe/bsw@0 | 220     do result = close(pipe_status[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 221     signal(SIGPIPE, old_sigpipe_action); | 
| jbe/bsw@0 | 222     if (status_pipe_len == 0) { | 
| jbe/bsw@0 | 223       if (WIFEXITED(exit_status)) lua_pushinteger(L, WEXITSTATUS(exit_status)); | 
| jbe/bsw@0 | 224       else lua_pushinteger(L, -WTERMSIG(exit_status)); | 
| jbe/bsw@0 | 225       return 3; | 
| jbe/bsw@0 | 226     } else if (status_buf[0] == 0) { | 
| jbe/bsw@0 | 227       return luaL_error(L, "Error in pfilter while reopening standard file descriptors in child process."); | 
| jbe/bsw@0 | 228     } else { | 
| jbe/bsw@0 | 229       strerror_r(status_buf[0], errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe/bsw@0 | 230       lua_pushnil(L); | 
| jbe/bsw@0 | 231       lua_pushfstring(L, "Could not execute \"%s\": %s", filename, errmsg); | 
| jbe/bsw@0 | 232       return 2; | 
| jbe/bsw@0 | 233     } | 
| jbe/bsw@0 | 234     extos_pfilter_error_B: | 
| jbe/bsw@0 | 235     signal(SIGPIPE, old_sigpipe_action); | 
| jbe/bsw@0 | 236     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe/bsw@0 | 237     if (out_buf) free(out_buf); | 
| jbe/bsw@0 | 238     if (err_buf) free(err_buf); | 
| jbe/bsw@0 | 239     if (!in_closed) { | 
| jbe/bsw@0 | 240       do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 241     } | 
| jbe/bsw@0 | 242     if (!out_closed) { | 
| jbe/bsw@0 | 243       do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 244     } | 
| jbe/bsw@0 | 245     if (!err_closed) { | 
| jbe/bsw@0 | 246       do result = close(pipe_err[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 247     } | 
| jbe/bsw@0 | 248     if (child) do result = waitpid(child, &exit_status, 0); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 249     return luaL_error(L, "Unexpected error in pfilter: %s", errmsg); | 
| jbe/bsw@0 | 250   } else {  // child | 
| jbe/bsw@0 | 251     do result = close(pipe_status[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 252     do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 253     do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 254     do result = close(0); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 255     do result = close(1); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 256     do result = close(2); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 257     do result = dup(pipe_in[0]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 258     if (result != 0) goto extos_pfilter_error_fd_remapping; | 
| jbe/bsw@0 | 259     do result = dup(pipe_out[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 260     if (result != 1) goto extos_pfilter_error_fd_remapping; | 
| jbe/bsw@0 | 261     do result = dup(pipe_err[1]); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 262     if (result != 2) goto extos_pfilter_error_fd_remapping; | 
| jbe/bsw@0 | 263     execvp(filename, args); | 
| jbe/bsw@0 | 264     status_buf[0] = errno; | 
| jbe/bsw@0 | 265     do result = write(pipe_status[1], status_buf, 1); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 266     _exit(0); | 
| jbe/bsw@0 | 267     extos_pfilter_error_fd_remapping: | 
| jbe/bsw@0 | 268     status_buf[0] = 0; | 
| jbe/bsw@0 | 269     do result = write(pipe_status[1], status_buf, 1); while (result < 0 && errno == EINTR); | 
| jbe/bsw@0 | 270     _exit(0); | 
| jbe/bsw@0 | 271   } | 
| jbe/bsw@0 | 272 } | 
| jbe/bsw@0 | 273 | 
| jbe/bsw@0 | 274 static int extos_listdir(lua_State *L) { | 
| jbe/bsw@0 | 275   DIR *dir; | 
| jbe/bsw@0 | 276   int i = 1; | 
| jbe/bsw@0 | 277   struct dirent entry_buffer; | 
| jbe/bsw@0 | 278   struct dirent *entry; | 
| jbe/bsw@0 | 279   dir = opendir(luaL_checkstring(L, 1)); | 
| jbe/bsw@0 | 280   if (!dir) { | 
| jbe/bsw@0 | 281     lua_pushnil(L); | 
| jbe/bsw@0 | 282     lua_pushliteral(L, "Could not list directory."); | 
| jbe/bsw@0 | 283     return 2; | 
| jbe/bsw@0 | 284   } | 
| jbe/bsw@0 | 285   lua_settop(L, 0); | 
| jbe/bsw@0 | 286   lua_newtable(L);  // 1 | 
| jbe/bsw@0 | 287   while (1) { | 
| jbe/bsw@0 | 288     readdir_r(dir, &entry_buffer, &entry); | 
| jbe/bsw@0 | 289     if (!entry) break; | 
| jbe/bsw@0 | 290     // Linux doesn't have d_namlen | 
| jbe/bsw@0 | 291     //lua_pushlstring(L, entry->d_name, entry->d_namlen); | 
| jbe/bsw@0 | 292     lua_pushstring(L, entry->d_name); | 
| jbe/bsw@0 | 293     lua_rawseti(L, 1, i++); | 
| jbe/bsw@0 | 294   } | 
| jbe/bsw@0 | 295   closedir(dir); | 
| jbe/bsw@0 | 296   return 1; | 
| jbe/bsw@0 | 297 } | 
| jbe/bsw@0 | 298 | 
| jbe@351 | 299 #define EXTOS_STAT_FOLLOW -1 | 
| jbe@351 | 300 #define EXTOS_STAT_NOFOLLOW -2 | 
| jbe@351 | 301 | 
| jbe@351 | 302 static int extos_stat_impl(lua_State *L, int fd) { | 
| jbe@344 | 303   struct stat sb; | 
| jbe@351 | 304   if (fd < 0) { | 
| jbe@351 | 305     const char *filename; | 
| jbe@351 | 306     filename = luaL_checkstring(L, 1); | 
| jbe@351 | 307     if (fd == EXTOS_STAT_FOLLOW ? stat(filename, &sb) : lstat(filename, &sb)) { | 
| jbe@351 | 308       char errmsg[EXTOS_MAX_ERRLEN+1]; | 
| jbe@351 | 309       strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe@351 | 310       if (errno == ENOENT) lua_pushboolean(L, 0); | 
| jbe@351 | 311       else lua_pushnil(L); | 
| jbe@351 | 312       lua_pushfstring(L, "Could not get file stats for \"%s\": %s", filename, errmsg); | 
| jbe@351 | 313       return 2; | 
| jbe@351 | 314     } | 
| jbe@351 | 315   } else { | 
| jbe@351 | 316     if (fstat(fd, &sb)) { | 
| jbe@351 | 317       char errmsg[EXTOS_MAX_ERRLEN+1]; | 
| jbe@351 | 318       strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); | 
| jbe@351 | 319       lua_pushnil(L); | 
| jbe@351 | 320       lua_pushfstring(L, "Could not get file stats for open file: %s", errmsg); | 
| jbe@351 | 321       return 2; | 
| jbe@351 | 322     } | 
| jbe@344 | 323   } | 
| jbe@344 | 324   lua_createtable(L, 0, 19); | 
| jbe@344 | 325   lua_pushinteger(L, sb.st_dev); | 
| jbe@344 | 326   lua_setfield(L, -2, "dev"); | 
| jbe@344 | 327   lua_pushinteger(L, sb.st_ino); | 
| jbe@344 | 328   lua_setfield(L, -2, "ino"); | 
| jbe@344 | 329   lua_pushinteger(L, sb.st_nlink); | 
| jbe@344 | 330   lua_setfield(L, -2, "nlink"); | 
| jbe@344 | 331   lua_pushinteger(L, sb.st_atime); | 
| jbe@344 | 332   lua_setfield(L, -2, "atime"); | 
| jbe@344 | 333   lua_pushinteger(L, sb.st_mtime); | 
| jbe@344 | 334   lua_setfield(L, -2, "mtime"); | 
| jbe@344 | 335   lua_pushinteger(L, sb.st_ctime); | 
| jbe@344 | 336   lua_setfield(L, -2, "ctime"); | 
| jbe@344 | 337   lua_pushinteger(L, sb.st_size); | 
| jbe@344 | 338   lua_setfield(L, -2, "size"); | 
| jbe@344 | 339   lua_pushinteger(L, sb.st_blksize); | 
| jbe@344 | 340   lua_setfield(L, -2, "blksize"); | 
| jbe@344 | 341   lua_pushinteger(L, sb.st_blocks); | 
| jbe@344 | 342   lua_setfield(L, -2, "blocks"); | 
| jbe@344 | 343   lua_pushinteger(L, sb.st_uid); | 
| jbe@344 | 344   lua_setfield(L, -2, "uid"); | 
| jbe@344 | 345   lua_pushinteger(L, sb.st_gid); | 
| jbe@344 | 346   lua_setfield(L, -2, "gid"); | 
| jbe@344 | 347   lua_pushinteger(L, sb.st_mode); | 
| jbe@344 | 348   lua_setfield(L, -2, "mode"); | 
| jbe@344 | 349   lua_pushboolean(L, S_ISBLK(sb.st_mode)); | 
| jbe@344 | 350   lua_setfield(L, -2, "isblk"); | 
| jbe@344 | 351   lua_pushboolean(L, S_ISCHR(sb.st_mode)); | 
| jbe@344 | 352   lua_setfield(L, -2, "ischr"); | 
| jbe@344 | 353   lua_pushboolean(L, S_ISDIR(sb.st_mode)); | 
| jbe@344 | 354   lua_setfield(L, -2, "isdir"); | 
| jbe@344 | 355   lua_pushboolean(L, S_ISFIFO(sb.st_mode)); | 
| jbe@344 | 356   lua_setfield(L, -2, "isfifo"); | 
| jbe@344 | 357   lua_pushboolean(L, S_ISLNK(sb.st_mode)); | 
| jbe@344 | 358   lua_setfield(L, -2, "islnk"); | 
| jbe@344 | 359   lua_pushboolean(L, S_ISREG(sb.st_mode)); | 
| jbe@344 | 360   lua_setfield(L, -2, "isreg"); | 
| jbe@344 | 361   lua_pushboolean(L, S_ISSOCK(sb.st_mode)); | 
| jbe@344 | 362   lua_setfield(L, -2, "issock"); | 
| jbe@344 | 363   return 1; | 
| jbe@344 | 364 } | 
| jbe@344 | 365 | 
| jbe@351 | 366 static int extos_stat(lua_State *L) { | 
| jbe@351 | 367   return extos_stat_impl(L, EXTOS_STAT_FOLLOW); | 
| jbe@351 | 368 } | 
| jbe@351 | 369 | 
| jbe@351 | 370 static int extos_lstat(lua_State *L) { | 
| jbe@351 | 371   return extos_stat_impl(L, EXTOS_STAT_NOFOLLOW); | 
| jbe@351 | 372 } | 
| jbe@351 | 373 | 
| jbe@351 | 374 static int extos_fstat(lua_State *L) { | 
| jbe@351 | 375   luaL_Stream *stream; | 
| jbe@351 | 376   stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); | 
| jbe@351 | 377   if (!stream->closef) luaL_error(L, "attempt to use a closed file"); | 
| jbe@351 | 378   return extos_stat_impl(L, fileno(stream->f)); | 
| jbe@351 | 379 } | 
| jbe@351 | 380 | 
| jbe/bsw@0 | 381 static int extos_crypt(lua_State *L) { | 
| jbe@343 | 382   const char *key; | 
| jbe@343 | 383   const char *salt; | 
| jbe/bsw@0 | 384   char *result; | 
| jbe/bsw@0 | 385   key = luaL_checkstring(L, 1); | 
| jbe/bsw@0 | 386   salt = luaL_checkstring(L, 2); | 
| jbe/bsw@0 | 387   result = crypt(key, salt);  // TODO: Call not thread safe | 
| jbe/bsw@0 | 388   if (result) lua_pushstring(L, result); | 
| jbe/bsw@0 | 389   else lua_pushnil(L); | 
| jbe/bsw@0 | 390   return 1; | 
| jbe/bsw@0 | 391 } | 
| jbe/bsw@0 | 392 | 
| jbe/bsw@0 | 393 static int extos_hires_time(lua_State *L) { | 
| jbe/bsw@0 | 394   struct timespec tp; | 
| jbe/bsw@0 | 395   if (clock_gettime(CLOCK_REALTIME, &tp)) { | 
| jbe/bsw@0 | 396     return luaL_error(L, "Could not access CLOCK_REALTIME."); | 
| jbe/bsw@0 | 397   } | 
| jbe@343 | 398   lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9); | 
| jbe/bsw@0 | 399   return 1; | 
| jbe/bsw@0 | 400 } | 
| jbe/bsw@0 | 401 | 
| jbe/bsw@0 | 402 // returns time in seconds since loading the library | 
| jbe/bsw@0 | 403 static int extos_monotonic_hires_time(lua_State *L) { | 
| jbe/bsw@0 | 404   struct timespec tp; | 
| jbe/bsw@0 | 405   if (clock_gettime(CLOCK_MONOTONIC, &tp)) { | 
| jbe/bsw@0 | 406     return luaL_error(L, "Could not access CLOCK_MONOTONIC."); | 
| jbe/bsw@0 | 407   } | 
| jbe/bsw@0 | 408   lua_pushnumber(L, | 
| jbe@343 | 409     tp.tv_sec + tp.tv_nsec / 1.0e9 - extos_monotonic_start_time | 
| jbe/bsw@0 | 410   ); | 
| jbe/bsw@0 | 411   return 1; | 
| jbe/bsw@0 | 412 } | 
| jbe/bsw@0 | 413 | 
| jbe@64 | 414 static const struct luaL_Reg extos_module_functions[] = { | 
| jbe@64 | 415   {"pfilter",              extos_pfilter}, | 
| jbe@64 | 416   {"listdir",              extos_listdir}, | 
| jbe@344 | 417   {"stat",                 extos_stat}, | 
| jbe@351 | 418   {"lstat",                extos_lstat}, | 
| jbe@351 | 419   {"fstat",                extos_fstat}, | 
| jbe@64 | 420   {"crypt",                extos_crypt}, | 
| jbe@64 | 421   {"hires_time",           extos_hires_time}, | 
| jbe@64 | 422   {"monotonic_hires_time", extos_monotonic_hires_time}, | 
| jbe@64 | 423   {NULL, NULL} | 
| jbe@64 | 424 }; | 
| jbe@64 | 425 | 
| jbe/bsw@0 | 426 int luaopen_extos(lua_State *L) { | 
| jbe/bsw@0 | 427   { | 
| jbe/bsw@0 | 428     struct timespec tp; | 
| jbe/bsw@0 | 429     if (clock_gettime(CLOCK_MONOTONIC, &tp)) { | 
| jbe/bsw@0 | 430       return luaL_error(L, "Could not access monotonic hires time."); | 
| jbe/bsw@0 | 431     } | 
| jbe@343 | 432     extos_monotonic_start_time = tp.tv_sec + tp.tv_nsec / 1.0e9; | 
| jbe/bsw@0 | 433   } | 
| jbe@64 | 434 #if LUA_VERSION_NUM >= 502 | 
| jbe@64 | 435   lua_newtable(L); | 
| jbe@64 | 436   luaL_setfuncs(L, extos_module_functions, 0); | 
| jbe@64 | 437 #else | 
| jbe@70 | 438   luaL_register(L, lua_tostring(L, 1), extos_module_functions); | 
| jbe@64 | 439 #endif | 
| jbe@64 | 440   return 1; | 
| jbe/bsw@0 | 441 } |