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