webmcp
view libraries/extos/extos.c @ 2:72860d232f32
Version 1.0.2
Fixed bug with explicit garbage collection (requests > 256kB caused an error)
Views prefixed with an underscore can't be called externally
ui.paginate now displays the last page, if the selected page number is too high.
Fixed bug with explicit garbage collection (requests > 256kB caused an error)
Views prefixed with an underscore can't be called externally
ui.paginate now displays the last page, if the selected page number is too high.
| author | jbe/bsw | 
|---|---|
| date | Thu Dec 10 12:00:00 2009 +0100 (2009-12-10) | 
| parents | 9fdfb27f8e67 | 
| children | 3d43a5cf17c1 | 
 line source
     1 #include <lua.h>
     2 #include <lauxlib.h>
     3 #include <dirent.h>
     4 #include <time.h>
     5 #include <unistd.h>
     6 #include <sys/types.h>
     7 #include <sys/wait.h>
     8 #include <signal.h>
     9 #include <errno.h>
    10 #include <stdio.h>
    11 #include <string.h>
    12 #include <fcntl.h>
    13 #include <poll.h>
    14 #include <stdlib.h>
    16 #define EXTOS_MAX_ERRLEN 80
    17 #define EXTOS_EXEC_MAX_ARGS 64
    19 static lua_Number extos_monotonic_start_time;
    21 static int extos_pfilter(lua_State *L) {
    22   int i, result, exit_status, status_pipe_len;
    23   const char *in_buf;
    24   size_t in_len;
    25   size_t in_pos = 0;
    26   const char *filename;
    27   const char *args[EXTOS_EXEC_MAX_ARGS+2];
    28   int pipe_status[2];
    29   int pipe_in[2];
    30   int pipe_out[2];
    31   int pipe_err[2];
    32   pid_t child;
    33   char status_buf[1];
    34   char *out_buf = NULL;
    35   size_t out_len = 1024;
    36   size_t out_pos = 0;
    37   char *err_buf = NULL;
    38   size_t err_len = 1024;
    39   size_t err_pos = 0;
    40   void *old_sigpipe_action;
    41   struct pollfd fds[3];
    42   int in_closed = 0;
    43   int out_closed = 0;
    44   int err_closed = 0;
    45   void *newptr;
    46   char errmsg[EXTOS_MAX_ERRLEN+1];
    47   in_buf = luaL_optlstring(L, 1, "", &in_len);
    48   filename = luaL_checkstring(L, 2);
    49   args[0] = filename;
    50   for (i = 0; i < EXTOS_EXEC_MAX_ARGS; i++) {
    51     if (lua_isnoneornil(L, 3+i)) break;
    52     else args[i+1] = luaL_checkstring(L, 3+i);
    53   }
    54   if (!lua_isnoneornil(L, 3+i)) {
    55     return luaL_error(L, "Too many arguments for pfilter call.");
    56   }
    57   args[i+1] = 0;
    58   // status pipe for internal communication
    59   if (pipe(pipe_status) < 0) {
    60     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1);
    61     goto extos_pfilter_error_A0;
    62   }
    63   // stdin
    64   if (pipe(pipe_in) < 0) {
    65     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1);
    66     goto extos_pfilter_error_A1;
    67   }
    68   if (in_len) {
    69     do result = fcntl(pipe_in[1], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR);
    70   } else {
    71     do result = close(pipe_in[1]); while (result < 0 && errno == EINTR);
    72     in_closed = 1;
    73   }
    74   if (result < 0) {
    75     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1);
    76     goto extos_pfilter_error_A2;
    77   }
    78   // stdout
    79   if (pipe(pipe_out) < 0) {
    80     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1);
    81     goto extos_pfilter_error_A2;
    82   }
    83   do result = fcntl(pipe_out[0], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR);
    84   if (result < 0) {
    85     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1);
    86     goto extos_pfilter_error_A3;
    87   }
    88   // stderr
    89   if (pipe(pipe_err) < 0) {
    90     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1);
    91     goto extos_pfilter_error_A3;
    92   }
    93   do result = fcntl(pipe_err[0], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR);
    94   if (result < 0) {
    95     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1);
    96     goto extos_pfilter_error_A4;
    97   }
    98   // fork
    99   child = fork();
   100   if (child < 0) {
   101     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1);
   102     goto extos_pfilter_error_A4;
   103   }
   104   // skip error handling
   105   goto extos_pfilter_success_A;
   106   // error handling
   107   extos_pfilter_error_A4:
   108   do result = close(pipe_err[0]); while (result < 0 && errno == EINTR);
   109   do result = close(pipe_err[1]); while (result < 0 && errno == EINTR);  
   110   extos_pfilter_error_A3:
   111   do result = close(pipe_out[0]); while (result < 0 && errno == EINTR);
   112   do result = close(pipe_out[1]); while (result < 0 && errno == EINTR);  
   113   extos_pfilter_error_A2:
   114   do result = close(pipe_in[0]); while (result < 0 && errno == EINTR);
   115   do result = close(pipe_in[1]); while (result < 0 && errno == EINTR);
   116   extos_pfilter_error_A1:
   117   do result = close(pipe_status[0]); while (result < 0 && errno == EINTR);
   118   do result = close(pipe_status[1]); while (result < 0 && errno == EINTR);  
   119   extos_pfilter_error_A0:
   120   return luaL_error(L, "Unexpected error in pfilter: %s", errmsg);
   121   // end of error handling
   122   extos_pfilter_success_A:
   123   if (child) {  // parent
   124     old_sigpipe_action = signal(SIGPIPE, SIG_IGN);
   125     do result = close(pipe_status[1]); while (result < 0 && errno == EINTR);
   126     if (result < 0) goto extos_pfilter_error_B;
   127     do result = close(pipe_in[0]); while (result < 0 && errno == EINTR);
   128     if (result < 0) goto extos_pfilter_error_B;
   129     do result = close(pipe_out[1]); while (result < 0 && errno == EINTR);
   130     if (result < 0) goto extos_pfilter_error_B;
   131     do result = close(pipe_err[1]); while (result < 0 && errno == EINTR);
   132     if (result < 0) goto extos_pfilter_error_B;
   133     out_buf = malloc(out_len * sizeof(char));
   134     if (!out_buf) goto extos_pfilter_error_B;
   135     err_buf = malloc(err_len * sizeof(char));
   136     if (!err_buf) goto extos_pfilter_error_B;
   137     while (!in_closed || !out_closed || !err_closed) {
   138       i = 0;
   139       if (!in_closed) {
   140         fds[i].fd = pipe_in[1];
   141         fds[i].events = POLLOUT;
   142         i++;
   143       }
   144       if (!out_closed) {
   145         fds[i].fd = pipe_out[0];
   146         fds[i].events = POLLIN;
   147         i++;
   148       }
   149       if (!err_closed) {
   150         fds[i].fd = pipe_err[0];
   151         fds[i].events = POLLIN;
   152         i++;
   153       }
   154       do result = poll(fds, i, -1); while (result < 0 && errno == EINTR);
   155       if (result < 0) goto extos_pfilter_error_B;
   156       if (!in_closed) {
   157         do result = write(pipe_in[1], in_buf+in_pos, in_len-in_pos); while (result < 0 && errno == EINTR);
   158         if (result < 0) {
   159           if (errno == EPIPE) {
   160             do result = close(pipe_in[1]); while (result < 0 && errno == EINTR);
   161             in_closed = 1;
   162           } else if (errno != EAGAIN) {
   163             goto extos_pfilter_error_B;
   164           }
   165         } else {
   166           in_pos += result;
   167           if (in_pos == in_len) {
   168             do result = close(pipe_in[1]); while (result < 0 && errno == EINTR);
   169             in_closed = 1;
   170           }
   171         }
   172       }
   173       if (!out_closed) {
   174         do result = read(pipe_out[0], out_buf+out_pos, out_len-out_pos); while (result < 0 && errno == EINTR);
   175         if (result < 0) {
   176           if (errno != EAGAIN) goto extos_pfilter_error_B;
   177         } else if (result == 0) {
   178           do result = close(pipe_out[0]); while (result < 0 && errno == EINTR);
   179           out_closed = 1;
   180         } else {
   181           out_pos += result;
   182           if (out_pos == out_len) {
   183             out_len *= 2;
   184             newptr = realloc(out_buf, out_len * sizeof(char));
   185             if (!newptr) goto extos_pfilter_error_B;
   186             out_buf = newptr;
   187           }
   188         }
   189       }
   190       if (!err_closed) {
   191         do result = read(pipe_err[0], err_buf+err_pos, err_len-err_pos); while (result < 0 && errno == EINTR);
   192         if (result < 0) {
   193           if (errno != EAGAIN) goto extos_pfilter_error_B;
   194         } else if (result == 0) {
   195           do result = close(pipe_err[0]); while (result < 0 && errno == EINTR);
   196           err_closed = 1;
   197         } else {
   198           err_pos += result;
   199           if (err_pos == err_len) {
   200             err_len *= 2;
   201             newptr = realloc(err_buf, err_len * sizeof(char));
   202             if (!newptr) goto extos_pfilter_error_B;
   203             err_buf = newptr;
   204           }
   205         }
   206       }
   207     }
   208     lua_pushlstring(L, out_buf, out_pos);
   209     free(out_buf);
   210     out_buf = NULL;
   211     lua_pushlstring(L, err_buf, err_pos);
   212     free(err_buf);
   213     err_buf = NULL;
   214     do result = waitpid(child, &exit_status, 0); while (result < 0 && errno == EINTR);
   215     child = 0;
   216     if (result < 0) goto extos_pfilter_error_B;
   217     do status_pipe_len = read(pipe_status[0], status_buf, 1); while (status_pipe_len < 0 && errno == EINTR);
   218     if (status_pipe_len < 0) goto extos_pfilter_error_B;
   219     do result = close(pipe_status[0]); while (result < 0 && errno == EINTR);
   220     signal(SIGPIPE, old_sigpipe_action);
   221     if (status_pipe_len == 0) {
   222       if (WIFEXITED(exit_status)) lua_pushinteger(L, WEXITSTATUS(exit_status));
   223       else lua_pushinteger(L, -WTERMSIG(exit_status));
   224       return 3;
   225     } else if (status_buf[0] == 0) {
   226       return luaL_error(L, "Error in pfilter while reopening standard file descriptors in child process.");
   227     } else {
   228       strerror_r(status_buf[0], errmsg, EXTOS_MAX_ERRLEN+1);
   229       lua_pushnil(L);
   230       lua_pushfstring(L, "Could not execute \"%s\": %s", filename, errmsg);
   231       return 2;
   232     }
   233     extos_pfilter_error_B:
   234     signal(SIGPIPE, old_sigpipe_action);
   235     strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1);
   236     if (out_buf) free(out_buf);
   237     if (err_buf) free(err_buf);
   238     if (!in_closed) {
   239       do result = close(pipe_in[1]); while (result < 0 && errno == EINTR);
   240     }
   241     if (!out_closed) {
   242       do result = close(pipe_out[0]); while (result < 0 && errno == EINTR);
   243     }
   244     if (!err_closed) {
   245       do result = close(pipe_err[0]); while (result < 0 && errno == EINTR);
   246     }
   247     if (child) do result = waitpid(child, &exit_status, 0); while (result < 0 && errno == EINTR);
   248     return luaL_error(L, "Unexpected error in pfilter: %s", errmsg);
   249   } else {  // child
   250     do result = close(pipe_status[0]); while (result < 0 && errno == EINTR);
   251     do result = close(pipe_in[1]); while (result < 0 && errno == EINTR);
   252     do result = close(pipe_out[0]); while (result < 0 && errno == EINTR);
   253     do result = close(0); while (result < 0 && errno == EINTR);
   254     do result = close(1); while (result < 0 && errno == EINTR);
   255     do result = close(2); while (result < 0 && errno == EINTR);
   256     do result = dup(pipe_in[0]); while (result < 0 && errno == EINTR);
   257     if (result != 0) goto extos_pfilter_error_fd_remapping;
   258     do result = dup(pipe_out[1]); while (result < 0 && errno == EINTR);
   259     if (result != 1) goto extos_pfilter_error_fd_remapping;
   260     do result = dup(pipe_err[1]); while (result < 0 && errno == EINTR);
   261     if (result != 2) goto extos_pfilter_error_fd_remapping;
   262     execvp(filename, args);
   263     status_buf[0] = errno;
   264     do result = write(pipe_status[1], status_buf, 1); while (result < 0 && errno == EINTR);
   265     _exit(0);
   266     extos_pfilter_error_fd_remapping:
   267     status_buf[0] = 0;
   268     do result = write(pipe_status[1], status_buf, 1); while (result < 0 && errno == EINTR);
   269     _exit(0);
   270   }
   271 }
   273 static int extos_listdir(lua_State *L) {
   274   DIR *dir;
   275   int i = 1;
   276   struct dirent entry_buffer;
   277   struct dirent *entry;
   278   dir = opendir(luaL_checkstring(L, 1));
   279   if (!dir) {
   280     lua_pushnil(L);
   281     lua_pushliteral(L, "Could not list directory.");
   282     return 2;
   283   }
   284   lua_settop(L, 0);
   285   lua_newtable(L);  // 1
   286   while (1) {
   287     readdir_r(dir, &entry_buffer, &entry);
   288     if (!entry) break;
   289     // Linux doesn't have d_namlen
   290     //lua_pushlstring(L, entry->d_name, entry->d_namlen);
   291     lua_pushstring(L, entry->d_name);
   292     lua_rawseti(L, 1, i++);
   293   }
   294   closedir(dir);
   295   return 1;
   296 }
   298 static int extos_crypt(lua_State *L) {
   299   char *key;
   300   char *salt;
   301   char *result;
   302   key = luaL_checkstring(L, 1);
   303   salt = luaL_checkstring(L, 2);
   304   result = crypt(key, salt);  // TODO: Call not thread safe
   305   if (result) lua_pushstring(L, result);
   306   else lua_pushnil(L);
   307   return 1;
   308 }
   310 static int extos_hires_time(lua_State *L) {
   311   struct timespec tp;
   312   if (clock_gettime(CLOCK_REALTIME, &tp)) {
   313     return luaL_error(L, "Could not access CLOCK_REALTIME.");
   314   }
   315   lua_pushnumber(L, tp.tv_sec + 0.000000001 * tp.tv_nsec);
   316   return 1;
   317 }
   319 // returns time in seconds since loading the library
   320 static int extos_monotonic_hires_time(lua_State *L) {
   321   struct timespec tp;
   322   if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
   323     return luaL_error(L, "Could not access CLOCK_MONOTONIC.");
   324   }
   325   lua_pushnumber(L,
   326     tp.tv_sec + 0.000000001 * tp.tv_nsec - extos_monotonic_start_time
   327   );
   328   return 1;
   329 }
   331 int luaopen_extos(lua_State *L) {
   332   {
   333     struct timespec tp;
   334     if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
   335       return luaL_error(L, "Could not access monotonic hires time.");
   336     }
   337     extos_monotonic_start_time = tp.tv_sec + 0.000000001 * tp.tv_nsec;
   338   }
   339   lua_getglobal(L, "os");
   340   lua_pushcfunction(L, extos_pfilter);
   341   lua_setfield(L, -2, "pfilter");
   342   lua_pushcfunction(L, extos_listdir);
   343   lua_setfield(L, -2, "listdir");
   344   lua_pushcfunction(L, extos_crypt);
   345   lua_setfield(L, -2, "crypt");
   346   lua_pushcfunction(L, extos_hires_time);
   347   lua_setfield(L, -2, "hires_time");
   348   lua_pushcfunction(L, extos_monotonic_hires_time);
   349   lua_setfield(L, -2, "monotonic_hires_time");
   350   return 0;
   351 }
