Fix stack overflow bug of uloop lua binding.
[project/libubox.git] / lua / uloop.c
1 /*
2 * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20
21 #include <lua.h>
22 #include <lualib.h>
23 #include <lauxlib.h>
24
25 #include "../uloop.h"
26 #include "../list.h"
27
28 struct lua_uloop_timeout {
29 struct uloop_timeout t;
30 int r;
31 };
32
33 struct lua_uloop_process {
34 struct uloop_process p;
35 int r;
36 };
37
38 static lua_State *state;
39
40 static void ul_timer_cb(struct uloop_timeout *t)
41 {
42 struct lua_uloop_timeout *tout = container_of(t, struct lua_uloop_timeout, t);
43
44 lua_getglobal(state, "__uloop_cb");
45 lua_rawgeti(state, -1, tout->r);
46 lua_remove(state, -2);
47 lua_call(state, 0, 0);
48 }
49
50 static int ul_timer_set(lua_State *L)
51 {
52 struct lua_uloop_timeout *tout;
53 double set;
54
55 if (!lua_isnumber(L, -1)) {
56 lua_pushstring(L, "invalid arg list");
57 lua_error(L);
58
59 return 0;
60 }
61
62 set = lua_tointeger(L, -1);
63 tout = lua_touserdata(L, 1);
64 uloop_timeout_set(&tout->t, set);
65
66 return 1;
67 }
68
69 static int ul_timer_free(lua_State *L)
70 {
71 struct lua_uloop_timeout *tout = lua_touserdata(L, 1);
72
73 uloop_timeout_cancel(&tout->t);
74 lua_getglobal(state, "__uloop_cb");
75 luaL_unref(L, -1, tout->r);
76
77 return 1;
78 }
79
80 static const luaL_Reg timer_m[] = {
81 { "set", ul_timer_set },
82 { "cancel", ul_timer_free },
83 { NULL, NULL }
84 };
85
86 static int ul_timer(lua_State *L)
87 {
88 struct lua_uloop_timeout *tout;
89 int set = 0;
90 int ref;
91
92 if (lua_isnumber(L, -1)) {
93 set = lua_tointeger(L, -1);
94 lua_pop(L, 1);
95 }
96
97 if (!lua_isfunction(L, -1)) {
98 lua_pushstring(L, "invalid arg list");
99 lua_error(L);
100
101 return 0;
102 }
103
104 lua_getglobal(L, "__uloop_cb");
105 lua_pushvalue(L, -2);
106 ref = luaL_ref(L, -2);
107
108 tout = lua_newuserdata(L, sizeof(*tout));
109 lua_createtable(L, 0, 2);
110 lua_pushvalue(L, -1);
111 lua_setfield(L, -2, "__index");
112 lua_pushcfunction(L, ul_timer_free);
113 lua_setfield(L, -2, "__gc");
114 lua_pushvalue(L, -1);
115 lua_setmetatable(L, -3);
116 lua_pushvalue(L, -2);
117 luaI_openlib(L, NULL, timer_m, 1);
118 lua_pushvalue(L, -2);
119
120 memset(tout, 0, sizeof(*tout));
121
122 tout->r = ref;
123 tout->t.cb = ul_timer_cb;
124 if (set)
125 uloop_timeout_set(&tout->t, set);
126
127 return 1;
128 }
129
130 static void ul_process_cb(struct uloop_process *p, int ret)
131 {
132 struct lua_uloop_process *proc = container_of(p, struct lua_uloop_process, p);
133
134 lua_getglobal(state, "__uloop_cb");
135 lua_rawgeti(state, -1, proc->r);
136 luaL_unref(state, -2, proc->r);
137 lua_remove(state, -2);
138 lua_pushinteger(state, ret >> 8);
139 lua_call(state, 1, 0);
140 }
141
142 static int ul_process(lua_State *L)
143 {
144 struct lua_uloop_process *proc;
145 pid_t pid;
146 int ref;
147
148 if (!lua_isfunction(L, -1) || !lua_istable(L, -2) ||
149 !lua_istable(L, -3) || !lua_isstring(L, -4)) {
150 lua_pushstring(L, "invalid arg list");
151 lua_error(L);
152
153 return 0;
154 }
155
156 pid = fork();
157
158 if (pid == -1) {
159 lua_pushstring(L, "failed to fork");
160 lua_error(L);
161
162 return 0;
163 }
164
165 if (pid == 0) {
166 /* child */
167 int argn = lua_objlen(L, -3);
168 int envn = lua_objlen(L, -2);
169 char** argp = malloc(sizeof(char*) * (argn + 2));
170 char** envp = malloc(sizeof(char*) * envn + 1);
171 int i = 1;
172
173 argp[0] = (char*) lua_tostring(L, -4);
174 for (i = 1; i <= argn; i++) {
175 lua_rawgeti(L, -3, i);
176 argp[i] = (char*) lua_tostring(L, -1);
177 lua_pop(L, 1);
178 }
179 argp[i] = NULL;
180
181 for (i = 1; i <= envn; i++) {
182 lua_rawgeti(L, -2, i);
183 envp[i - 1] = (char*) lua_tostring(L, -1);
184 lua_pop(L, 1);
185 }
186 envp[i - 1] = NULL;
187
188 execve(*argp, argp, envp);
189 exit(-1);
190 }
191
192 lua_getglobal(L, "__uloop_cb");
193 lua_pushvalue(L, -2);
194 ref = luaL_ref(L, -2);
195
196 proc = lua_newuserdata(L, sizeof(*proc));
197 memset(proc, 0, sizeof(*proc));
198
199 proc->r = ref;
200 proc->p.pid = pid;
201 proc->p.cb = ul_process_cb;
202 uloop_process_add(&proc->p);
203
204 return 1;
205 }
206
207 static int ul_init(lua_State *L)
208 {
209 uloop_init();
210 lua_pushboolean(L, 1);
211
212 return 1;
213 }
214
215 static int ul_run(lua_State *L)
216 {
217 uloop_run();
218 lua_pushboolean(L, 1);
219
220 return 1;
221 }
222
223 static luaL_reg uloop_func[] = {
224 {"init", ul_init},
225 {"run", ul_run},
226 {"timer", ul_timer},
227 {"process", ul_process},
228 {NULL, NULL},
229 };
230
231 /* avoid warnings about missing declarations */
232 int luaopen_uloop(lua_State *L);
233 int luaclose_uloop(lua_State *L);
234
235 int luaopen_uloop(lua_State *L)
236 {
237 state = L;
238
239 lua_createtable(L, 1, 0);
240 lua_setglobal(L, "__uloop_cb");
241
242 luaL_openlib(L, "uloop", uloop_func, 0);
243 lua_pushstring(L, "_VERSION");
244 lua_pushstring(L, "1.0");
245 lua_rawset(L, -3);
246
247 return 1;
248 }
249
250 int luaclose_uloop(lua_State *L)
251 {
252 lua_pushstring(L, "Called");
253
254 return 1;
255 }