| 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@344
 | 
   299 static int extos_stat(lua_State *L) {
 | 
| 
jbe@344
 | 
   300   const char *filename;
 | 
| 
jbe@344
 | 
   301   struct stat sb;
 | 
| 
jbe@344
 | 
   302   filename = luaL_checkstring(L, 1);
 | 
| 
jbe@344
 | 
   303   if (stat(filename, &sb)) {
 | 
| 
jbe@344
 | 
   304     char errmsg[EXTOS_MAX_ERRLEN+1];
 | 
| 
jbe@344
 | 
   305     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1);
 | 
| 
jbe@344
 | 
   306     lua_pushnil(L);
 | 
| 
jbe@344
 | 
   307     lua_pushfstring(L, "Could not get file stats for \"%s\": %s", filename, errmsg);
 | 
| 
jbe@344
 | 
   308     return 2;
 | 
| 
jbe@344
 | 
   309   }
 | 
| 
jbe@344
 | 
   310   lua_createtable(L, 0, 19);
 | 
| 
jbe@344
 | 
   311   lua_pushinteger(L, sb.st_dev);
 | 
| 
jbe@344
 | 
   312   lua_setfield(L, -2, "dev");
 | 
| 
jbe@344
 | 
   313   lua_pushinteger(L, sb.st_ino);
 | 
| 
jbe@344
 | 
   314   lua_setfield(L, -2, "ino");
 | 
| 
jbe@344
 | 
   315   lua_pushinteger(L, sb.st_nlink);
 | 
| 
jbe@344
 | 
   316   lua_setfield(L, -2, "nlink");
 | 
| 
jbe@344
 | 
   317   lua_pushinteger(L, sb.st_atime);
 | 
| 
jbe@344
 | 
   318   lua_setfield(L, -2, "atime");
 | 
| 
jbe@344
 | 
   319   lua_pushinteger(L, sb.st_mtime);
 | 
| 
jbe@344
 | 
   320   lua_setfield(L, -2, "mtime");
 | 
| 
jbe@344
 | 
   321   lua_pushinteger(L, sb.st_ctime);
 | 
| 
jbe@344
 | 
   322   lua_setfield(L, -2, "ctime");
 | 
| 
jbe@344
 | 
   323   lua_pushinteger(L, sb.st_size);
 | 
| 
jbe@344
 | 
   324   lua_setfield(L, -2, "size");
 | 
| 
jbe@344
 | 
   325   lua_pushinteger(L, sb.st_blksize);
 | 
| 
jbe@344
 | 
   326   lua_setfield(L, -2, "blksize");
 | 
| 
jbe@344
 | 
   327   lua_pushinteger(L, sb.st_blocks);
 | 
| 
jbe@344
 | 
   328   lua_setfield(L, -2, "blocks");
 | 
| 
jbe@344
 | 
   329   lua_pushinteger(L, sb.st_uid);
 | 
| 
jbe@344
 | 
   330   lua_setfield(L, -2, "uid");
 | 
| 
jbe@344
 | 
   331   lua_pushinteger(L, sb.st_gid);
 | 
| 
jbe@344
 | 
   332   lua_setfield(L, -2, "gid");
 | 
| 
jbe@344
 | 
   333   lua_pushinteger(L, sb.st_mode);
 | 
| 
jbe@344
 | 
   334   lua_setfield(L, -2, "mode");
 | 
| 
jbe@344
 | 
   335   lua_pushboolean(L, S_ISBLK(sb.st_mode));
 | 
| 
jbe@344
 | 
   336   lua_setfield(L, -2, "isblk");
 | 
| 
jbe@344
 | 
   337   lua_pushboolean(L, S_ISCHR(sb.st_mode));
 | 
| 
jbe@344
 | 
   338   lua_setfield(L, -2, "ischr");
 | 
| 
jbe@344
 | 
   339   lua_pushboolean(L, S_ISDIR(sb.st_mode));
 | 
| 
jbe@344
 | 
   340   lua_setfield(L, -2, "isdir");
 | 
| 
jbe@344
 | 
   341   lua_pushboolean(L, S_ISFIFO(sb.st_mode));
 | 
| 
jbe@344
 | 
   342   lua_setfield(L, -2, "isfifo");
 | 
| 
jbe@344
 | 
   343   lua_pushboolean(L, S_ISLNK(sb.st_mode));
 | 
| 
jbe@344
 | 
   344   lua_setfield(L, -2, "islnk");
 | 
| 
jbe@344
 | 
   345   lua_pushboolean(L, S_ISREG(sb.st_mode));
 | 
| 
jbe@344
 | 
   346   lua_setfield(L, -2, "isreg");
 | 
| 
jbe@344
 | 
   347   lua_pushboolean(L, S_ISSOCK(sb.st_mode));
 | 
| 
jbe@344
 | 
   348   lua_setfield(L, -2, "issock");
 | 
| 
jbe@344
 | 
   349   return 1;
 | 
| 
jbe@344
 | 
   350 }
 | 
| 
jbe@344
 | 
   351 
 | 
| 
jbe/bsw@0
 | 
   352 static int extos_crypt(lua_State *L) {
 | 
| 
jbe@343
 | 
   353   const char *key;
 | 
| 
jbe@343
 | 
   354   const char *salt;
 | 
| 
jbe/bsw@0
 | 
   355   char *result;
 | 
| 
jbe/bsw@0
 | 
   356   key = luaL_checkstring(L, 1);
 | 
| 
jbe/bsw@0
 | 
   357   salt = luaL_checkstring(L, 2);
 | 
| 
jbe/bsw@0
 | 
   358   result = crypt(key, salt);  // TODO: Call not thread safe
 | 
| 
jbe/bsw@0
 | 
   359   if (result) lua_pushstring(L, result);
 | 
| 
jbe/bsw@0
 | 
   360   else lua_pushnil(L);
 | 
| 
jbe/bsw@0
 | 
   361   return 1;
 | 
| 
jbe/bsw@0
 | 
   362 }
 | 
| 
jbe/bsw@0
 | 
   363 
 | 
| 
jbe/bsw@0
 | 
   364 static int extos_hires_time(lua_State *L) {
 | 
| 
jbe/bsw@0
 | 
   365   struct timespec tp;
 | 
| 
jbe/bsw@0
 | 
   366   if (clock_gettime(CLOCK_REALTIME, &tp)) {
 | 
| 
jbe/bsw@0
 | 
   367     return luaL_error(L, "Could not access CLOCK_REALTIME.");
 | 
| 
jbe/bsw@0
 | 
   368   }
 | 
| 
jbe@343
 | 
   369   lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9);
 | 
| 
jbe/bsw@0
 | 
   370   return 1;
 | 
| 
jbe/bsw@0
 | 
   371 }
 | 
| 
jbe/bsw@0
 | 
   372 
 | 
| 
jbe/bsw@0
 | 
   373 // returns time in seconds since loading the library
 | 
| 
jbe/bsw@0
 | 
   374 static int extos_monotonic_hires_time(lua_State *L) {
 | 
| 
jbe/bsw@0
 | 
   375   struct timespec tp;
 | 
| 
jbe/bsw@0
 | 
   376   if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
 | 
| 
jbe/bsw@0
 | 
   377     return luaL_error(L, "Could not access CLOCK_MONOTONIC.");
 | 
| 
jbe/bsw@0
 | 
   378   }
 | 
| 
jbe/bsw@0
 | 
   379   lua_pushnumber(L,
 | 
| 
jbe@343
 | 
   380     tp.tv_sec + tp.tv_nsec / 1.0e9 - extos_monotonic_start_time
 | 
| 
jbe/bsw@0
 | 
   381   );
 | 
| 
jbe/bsw@0
 | 
   382   return 1;
 | 
| 
jbe/bsw@0
 | 
   383 }
 | 
| 
jbe/bsw@0
 | 
   384 
 | 
| 
jbe@64
 | 
   385 static const struct luaL_Reg extos_module_functions[] = {
 | 
| 
jbe@64
 | 
   386   {"pfilter",              extos_pfilter},
 | 
| 
jbe@64
 | 
   387   {"listdir",              extos_listdir},
 | 
| 
jbe@344
 | 
   388   {"stat",                 extos_stat},
 | 
| 
jbe@64
 | 
   389   {"crypt",                extos_crypt},
 | 
| 
jbe@64
 | 
   390   {"hires_time",           extos_hires_time},
 | 
| 
jbe@64
 | 
   391   {"monotonic_hires_time", extos_monotonic_hires_time},
 | 
| 
jbe@64
 | 
   392   {NULL, NULL}
 | 
| 
jbe@64
 | 
   393 };
 | 
| 
jbe@64
 | 
   394 
 | 
| 
jbe/bsw@0
 | 
   395 int luaopen_extos(lua_State *L) {
 | 
| 
jbe/bsw@0
 | 
   396   {
 | 
| 
jbe/bsw@0
 | 
   397     struct timespec tp;
 | 
| 
jbe/bsw@0
 | 
   398     if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
 | 
| 
jbe/bsw@0
 | 
   399       return luaL_error(L, "Could not access monotonic hires time.");
 | 
| 
jbe/bsw@0
 | 
   400     }
 | 
| 
jbe@343
 | 
   401     extos_monotonic_start_time = tp.tv_sec + tp.tv_nsec / 1.0e9;
 | 
| 
jbe/bsw@0
 | 
   402   }
 | 
| 
jbe@64
 | 
   403 #if LUA_VERSION_NUM >= 502
 | 
| 
jbe@64
 | 
   404   lua_newtable(L);
 | 
| 
jbe@64
 | 
   405   luaL_setfuncs(L, extos_module_functions, 0);
 | 
| 
jbe@64
 | 
   406 #else
 | 
| 
jbe@70
 | 
   407   luaL_register(L, lua_tostring(L, 1), extos_module_functions);
 | 
| 
jbe@64
 | 
   408 #endif
 | 
| 
jbe@64
 | 
   409   return 1;
 | 
| 
jbe/bsw@0
 | 
   410 }
 |