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 }