webmcp
diff libraries/extos/extos.c @ 0:9fdfb27f8e67
Version 1.0.0
author | jbe/bsw |
---|---|
date | Sun Oct 25 12:00:00 2009 +0100 (2009-10-25) |
parents | |
children | 3d43a5cf17c1 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libraries/extos/extos.c Sun Oct 25 12:00:00 2009 +0100 1.3 @@ -0,0 +1,351 @@ 1.4 +#include <lua.h> 1.5 +#include <lauxlib.h> 1.6 +#include <dirent.h> 1.7 +#include <time.h> 1.8 +#include <unistd.h> 1.9 +#include <sys/types.h> 1.10 +#include <sys/wait.h> 1.11 +#include <signal.h> 1.12 +#include <errno.h> 1.13 +#include <stdio.h> 1.14 +#include <string.h> 1.15 +#include <fcntl.h> 1.16 +#include <poll.h> 1.17 +#include <stdlib.h> 1.18 + 1.19 +#define EXTOS_MAX_ERRLEN 80 1.20 +#define EXTOS_EXEC_MAX_ARGS 64 1.21 + 1.22 +static lua_Number extos_monotonic_start_time; 1.23 + 1.24 +static int extos_pfilter(lua_State *L) { 1.25 + int i, result, exit_status, status_pipe_len; 1.26 + const char *in_buf; 1.27 + size_t in_len; 1.28 + size_t in_pos = 0; 1.29 + const char *filename; 1.30 + const char *args[EXTOS_EXEC_MAX_ARGS+2]; 1.31 + int pipe_status[2]; 1.32 + int pipe_in[2]; 1.33 + int pipe_out[2]; 1.34 + int pipe_err[2]; 1.35 + pid_t child; 1.36 + char status_buf[1]; 1.37 + char *out_buf = NULL; 1.38 + size_t out_len = 1024; 1.39 + size_t out_pos = 0; 1.40 + char *err_buf = NULL; 1.41 + size_t err_len = 1024; 1.42 + size_t err_pos = 0; 1.43 + void *old_sigpipe_action; 1.44 + struct pollfd fds[3]; 1.45 + int in_closed = 0; 1.46 + int out_closed = 0; 1.47 + int err_closed = 0; 1.48 + void *newptr; 1.49 + char errmsg[EXTOS_MAX_ERRLEN+1]; 1.50 + in_buf = luaL_optlstring(L, 1, "", &in_len); 1.51 + filename = luaL_checkstring(L, 2); 1.52 + args[0] = filename; 1.53 + for (i = 0; i < EXTOS_EXEC_MAX_ARGS; i++) { 1.54 + if (lua_isnoneornil(L, 3+i)) break; 1.55 + else args[i+1] = luaL_checkstring(L, 3+i); 1.56 + } 1.57 + if (!lua_isnoneornil(L, 3+i)) { 1.58 + return luaL_error(L, "Too many arguments for pfilter call."); 1.59 + } 1.60 + args[i+1] = 0; 1.61 + // status pipe for internal communication 1.62 + if (pipe(pipe_status) < 0) { 1.63 + strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); 1.64 + goto extos_pfilter_error_A0; 1.65 + } 1.66 + // stdin 1.67 + if (pipe(pipe_in) < 0) { 1.68 + strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); 1.69 + goto extos_pfilter_error_A1; 1.70 + } 1.71 + if (in_len) { 1.72 + do result = fcntl(pipe_in[1], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR); 1.73 + } else { 1.74 + do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); 1.75 + in_closed = 1; 1.76 + } 1.77 + if (result < 0) { 1.78 + strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); 1.79 + goto extos_pfilter_error_A2; 1.80 + } 1.81 + // stdout 1.82 + if (pipe(pipe_out) < 0) { 1.83 + strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); 1.84 + goto extos_pfilter_error_A2; 1.85 + } 1.86 + do result = fcntl(pipe_out[0], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR); 1.87 + if (result < 0) { 1.88 + strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); 1.89 + goto extos_pfilter_error_A3; 1.90 + } 1.91 + // stderr 1.92 + if (pipe(pipe_err) < 0) { 1.93 + strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); 1.94 + goto extos_pfilter_error_A3; 1.95 + } 1.96 + do result = fcntl(pipe_err[0], F_SETFL, O_NONBLOCK); while (result < 0 && errno == EINTR); 1.97 + if (result < 0) { 1.98 + strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); 1.99 + goto extos_pfilter_error_A4; 1.100 + } 1.101 + // fork 1.102 + child = fork(); 1.103 + if (child < 0) { 1.104 + strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); 1.105 + goto extos_pfilter_error_A4; 1.106 + } 1.107 + // skip error handling 1.108 + goto extos_pfilter_success_A; 1.109 + // error handling 1.110 + extos_pfilter_error_A4: 1.111 + do result = close(pipe_err[0]); while (result < 0 && errno == EINTR); 1.112 + do result = close(pipe_err[1]); while (result < 0 && errno == EINTR); 1.113 + extos_pfilter_error_A3: 1.114 + do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); 1.115 + do result = close(pipe_out[1]); while (result < 0 && errno == EINTR); 1.116 + extos_pfilter_error_A2: 1.117 + do result = close(pipe_in[0]); while (result < 0 && errno == EINTR); 1.118 + do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); 1.119 + extos_pfilter_error_A1: 1.120 + do result = close(pipe_status[0]); while (result < 0 && errno == EINTR); 1.121 + do result = close(pipe_status[1]); while (result < 0 && errno == EINTR); 1.122 + extos_pfilter_error_A0: 1.123 + return luaL_error(L, "Unexpected error in pfilter: %s", errmsg); 1.124 + // end of error handling 1.125 + extos_pfilter_success_A: 1.126 + if (child) { // parent 1.127 + old_sigpipe_action = signal(SIGPIPE, SIG_IGN); 1.128 + do result = close(pipe_status[1]); while (result < 0 && errno == EINTR); 1.129 + if (result < 0) goto extos_pfilter_error_B; 1.130 + do result = close(pipe_in[0]); while (result < 0 && errno == EINTR); 1.131 + if (result < 0) goto extos_pfilter_error_B; 1.132 + do result = close(pipe_out[1]); while (result < 0 && errno == EINTR); 1.133 + if (result < 0) goto extos_pfilter_error_B; 1.134 + do result = close(pipe_err[1]); while (result < 0 && errno == EINTR); 1.135 + if (result < 0) goto extos_pfilter_error_B; 1.136 + out_buf = malloc(out_len * sizeof(char)); 1.137 + if (!out_buf) goto extos_pfilter_error_B; 1.138 + err_buf = malloc(err_len * sizeof(char)); 1.139 + if (!err_buf) goto extos_pfilter_error_B; 1.140 + while (!in_closed || !out_closed || !err_closed) { 1.141 + i = 0; 1.142 + if (!in_closed) { 1.143 + fds[i].fd = pipe_in[1]; 1.144 + fds[i].events = POLLOUT; 1.145 + i++; 1.146 + } 1.147 + if (!out_closed) { 1.148 + fds[i].fd = pipe_out[0]; 1.149 + fds[i].events = POLLIN; 1.150 + i++; 1.151 + } 1.152 + if (!err_closed) { 1.153 + fds[i].fd = pipe_err[0]; 1.154 + fds[i].events = POLLIN; 1.155 + i++; 1.156 + } 1.157 + do result = poll(fds, i, -1); while (result < 0 && errno == EINTR); 1.158 + if (result < 0) goto extos_pfilter_error_B; 1.159 + if (!in_closed) { 1.160 + do result = write(pipe_in[1], in_buf+in_pos, in_len-in_pos); while (result < 0 && errno == EINTR); 1.161 + if (result < 0) { 1.162 + if (errno == EPIPE) { 1.163 + do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); 1.164 + in_closed = 1; 1.165 + } else if (errno != EAGAIN) { 1.166 + goto extos_pfilter_error_B; 1.167 + } 1.168 + } else { 1.169 + in_pos += result; 1.170 + if (in_pos == in_len) { 1.171 + do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); 1.172 + in_closed = 1; 1.173 + } 1.174 + } 1.175 + } 1.176 + if (!out_closed) { 1.177 + do result = read(pipe_out[0], out_buf+out_pos, out_len-out_pos); while (result < 0 && errno == EINTR); 1.178 + if (result < 0) { 1.179 + if (errno != EAGAIN) goto extos_pfilter_error_B; 1.180 + } else if (result == 0) { 1.181 + do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); 1.182 + out_closed = 1; 1.183 + } else { 1.184 + out_pos += result; 1.185 + if (out_pos == out_len) { 1.186 + out_len *= 2; 1.187 + newptr = realloc(out_buf, out_len * sizeof(char)); 1.188 + if (!newptr) goto extos_pfilter_error_B; 1.189 + out_buf = newptr; 1.190 + } 1.191 + } 1.192 + } 1.193 + if (!err_closed) { 1.194 + do result = read(pipe_err[0], err_buf+err_pos, err_len-err_pos); while (result < 0 && errno == EINTR); 1.195 + if (result < 0) { 1.196 + if (errno != EAGAIN) goto extos_pfilter_error_B; 1.197 + } else if (result == 0) { 1.198 + do result = close(pipe_err[0]); while (result < 0 && errno == EINTR); 1.199 + err_closed = 1; 1.200 + } else { 1.201 + err_pos += result; 1.202 + if (err_pos == err_len) { 1.203 + err_len *= 2; 1.204 + newptr = realloc(err_buf, err_len * sizeof(char)); 1.205 + if (!newptr) goto extos_pfilter_error_B; 1.206 + err_buf = newptr; 1.207 + } 1.208 + } 1.209 + } 1.210 + } 1.211 + lua_pushlstring(L, out_buf, out_pos); 1.212 + free(out_buf); 1.213 + out_buf = NULL; 1.214 + lua_pushlstring(L, err_buf, err_pos); 1.215 + free(err_buf); 1.216 + err_buf = NULL; 1.217 + do result = waitpid(child, &exit_status, 0); while (result < 0 && errno == EINTR); 1.218 + child = 0; 1.219 + if (result < 0) goto extos_pfilter_error_B; 1.220 + do status_pipe_len = read(pipe_status[0], status_buf, 1); while (status_pipe_len < 0 && errno == EINTR); 1.221 + if (status_pipe_len < 0) goto extos_pfilter_error_B; 1.222 + do result = close(pipe_status[0]); while (result < 0 && errno == EINTR); 1.223 + signal(SIGPIPE, old_sigpipe_action); 1.224 + if (status_pipe_len == 0) { 1.225 + if (WIFEXITED(exit_status)) lua_pushinteger(L, WEXITSTATUS(exit_status)); 1.226 + else lua_pushinteger(L, -WTERMSIG(exit_status)); 1.227 + return 3; 1.228 + } else if (status_buf[0] == 0) { 1.229 + return luaL_error(L, "Error in pfilter while reopening standard file descriptors in child process."); 1.230 + } else { 1.231 + strerror_r(status_buf[0], errmsg, EXTOS_MAX_ERRLEN+1); 1.232 + lua_pushnil(L); 1.233 + lua_pushfstring(L, "Could not execute \"%s\": %s", filename, errmsg); 1.234 + return 2; 1.235 + } 1.236 + extos_pfilter_error_B: 1.237 + signal(SIGPIPE, old_sigpipe_action); 1.238 + strerror_r(errno, errmsg, EXTOS_MAX_ERRLEN+1); 1.239 + if (out_buf) free(out_buf); 1.240 + if (err_buf) free(err_buf); 1.241 + if (!in_closed) { 1.242 + do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); 1.243 + } 1.244 + if (!out_closed) { 1.245 + do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); 1.246 + } 1.247 + if (!err_closed) { 1.248 + do result = close(pipe_err[0]); while (result < 0 && errno == EINTR); 1.249 + } 1.250 + if (child) do result = waitpid(child, &exit_status, 0); while (result < 0 && errno == EINTR); 1.251 + return luaL_error(L, "Unexpected error in pfilter: %s", errmsg); 1.252 + } else { // child 1.253 + do result = close(pipe_status[0]); while (result < 0 && errno == EINTR); 1.254 + do result = close(pipe_in[1]); while (result < 0 && errno == EINTR); 1.255 + do result = close(pipe_out[0]); while (result < 0 && errno == EINTR); 1.256 + do result = close(0); while (result < 0 && errno == EINTR); 1.257 + do result = close(1); while (result < 0 && errno == EINTR); 1.258 + do result = close(2); while (result < 0 && errno == EINTR); 1.259 + do result = dup(pipe_in[0]); while (result < 0 && errno == EINTR); 1.260 + if (result != 0) goto extos_pfilter_error_fd_remapping; 1.261 + do result = dup(pipe_out[1]); while (result < 0 && errno == EINTR); 1.262 + if (result != 1) goto extos_pfilter_error_fd_remapping; 1.263 + do result = dup(pipe_err[1]); while (result < 0 && errno == EINTR); 1.264 + if (result != 2) goto extos_pfilter_error_fd_remapping; 1.265 + execvp(filename, args); 1.266 + status_buf[0] = errno; 1.267 + do result = write(pipe_status[1], status_buf, 1); while (result < 0 && errno == EINTR); 1.268 + _exit(0); 1.269 + extos_pfilter_error_fd_remapping: 1.270 + status_buf[0] = 0; 1.271 + do result = write(pipe_status[1], status_buf, 1); while (result < 0 && errno == EINTR); 1.272 + _exit(0); 1.273 + } 1.274 +} 1.275 + 1.276 +static int extos_listdir(lua_State *L) { 1.277 + DIR *dir; 1.278 + int i = 1; 1.279 + struct dirent entry_buffer; 1.280 + struct dirent *entry; 1.281 + dir = opendir(luaL_checkstring(L, 1)); 1.282 + if (!dir) { 1.283 + lua_pushnil(L); 1.284 + lua_pushliteral(L, "Could not list directory."); 1.285 + return 2; 1.286 + } 1.287 + lua_settop(L, 0); 1.288 + lua_newtable(L); // 1 1.289 + while (1) { 1.290 + readdir_r(dir, &entry_buffer, &entry); 1.291 + if (!entry) break; 1.292 + // Linux doesn't have d_namlen 1.293 + //lua_pushlstring(L, entry->d_name, entry->d_namlen); 1.294 + lua_pushstring(L, entry->d_name); 1.295 + lua_rawseti(L, 1, i++); 1.296 + } 1.297 + closedir(dir); 1.298 + return 1; 1.299 +} 1.300 + 1.301 +static int extos_crypt(lua_State *L) { 1.302 + char *key; 1.303 + char *salt; 1.304 + char *result; 1.305 + key = luaL_checkstring(L, 1); 1.306 + salt = luaL_checkstring(L, 2); 1.307 + result = crypt(key, salt); // TODO: Call not thread safe 1.308 + if (result) lua_pushstring(L, result); 1.309 + else lua_pushnil(L); 1.310 + return 1; 1.311 +} 1.312 + 1.313 +static int extos_hires_time(lua_State *L) { 1.314 + struct timespec tp; 1.315 + if (clock_gettime(CLOCK_REALTIME, &tp)) { 1.316 + return luaL_error(L, "Could not access CLOCK_REALTIME."); 1.317 + } 1.318 + lua_pushnumber(L, tp.tv_sec + 0.000000001 * tp.tv_nsec); 1.319 + return 1; 1.320 +} 1.321 + 1.322 +// returns time in seconds since loading the library 1.323 +static int extos_monotonic_hires_time(lua_State *L) { 1.324 + struct timespec tp; 1.325 + if (clock_gettime(CLOCK_MONOTONIC, &tp)) { 1.326 + return luaL_error(L, "Could not access CLOCK_MONOTONIC."); 1.327 + } 1.328 + lua_pushnumber(L, 1.329 + tp.tv_sec + 0.000000001 * tp.tv_nsec - extos_monotonic_start_time 1.330 + ); 1.331 + return 1; 1.332 +} 1.333 + 1.334 +int luaopen_extos(lua_State *L) { 1.335 + { 1.336 + struct timespec tp; 1.337 + if (clock_gettime(CLOCK_MONOTONIC, &tp)) { 1.338 + return luaL_error(L, "Could not access monotonic hires time."); 1.339 + } 1.340 + extos_monotonic_start_time = tp.tv_sec + 0.000000001 * tp.tv_nsec; 1.341 + } 1.342 + lua_getglobal(L, "os"); 1.343 + lua_pushcfunction(L, extos_pfilter); 1.344 + lua_setfield(L, -2, "pfilter"); 1.345 + lua_pushcfunction(L, extos_listdir); 1.346 + lua_setfield(L, -2, "listdir"); 1.347 + lua_pushcfunction(L, extos_crypt); 1.348 + lua_setfield(L, -2, "crypt"); 1.349 + lua_pushcfunction(L, extos_hires_time); 1.350 + lua_setfield(L, -2, "hires_time"); 1.351 + lua_pushcfunction(L, extos_monotonic_hires_time); 1.352 + lua_setfield(L, -2, "monotonic_hires_time"); 1.353 + return 0; 1.354 +}