45c06a644e77ad0cbc6a9f4b0dd8bb2d61c16f6d
[project/luci.git] / libs / nixio / src / process.c
1 /*
2  * nixio - Linux I/O library for lua
3  *
4  *   Copyright (C) 2009 Steven Barth <steven@midlink.org>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18
19 #include "nixio.h"
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <signal.h>
27
28 #define NIXIO_EXECVE    0x01
29 #define NIXIO_EXECV             0x02
30 #define NIXIO_EXECVP    0x03
31
32 int nixio__exec(lua_State *L, int m) {
33         const char *path = luaL_checkstring(L, 1);
34         const char *arg;
35         int argn, i;
36
37         if (m == NIXIO_EXECVE) {
38                 luaL_checktype(L, 2, LUA_TTABLE);
39                 argn = lua_objlen(L, 2) + 1;
40         } else {
41                 argn = lua_gettop(L);
42         }
43
44         char **args = lua_newuserdata(L, sizeof(char*) * (argn + 1));
45         args[argn] = NULL;
46         args[0] = (char *)path;
47
48         if (m == NIXIO_EXECVE) {
49                 for (i = 1; i < argn; i++) {
50                         lua_rawgeti(L, 2, i);
51                         arg = lua_tostring(L, -1);
52                         luaL_argcheck(L, arg, 2, "invalid argument");
53                         args[i] = (char *)arg;
54                 }
55
56                 if (lua_isnoneornil(L, 3)) {
57                         execv(path, args);
58                 } else {
59                         luaL_checktype(L, 3, LUA_TTABLE);
60                         argn = 0;
61                         lua_pushnil(L);
62                         while (lua_next(L, 3)) {
63                                 if (!lua_checkstack(L, 1)) {
64                                         lua_settop(L, 0);
65                                         return luaL_error(L, "stack overflow");
66                                 }
67
68                                 if (!lua_type(L, -2) != LUA_TSTRING || !lua_isstring(L, -1)) {
69                                         return luaL_argerror(L, 3, "invalid environment");
70                                 }
71
72                                 lua_pushfstring(L, "%s=%s",
73                                                 lua_tostring(L, -2), lua_tostring(L, -1));
74
75                                 lua_insert(L, 4);
76                                 lua_pop(L, 1);
77                                 argn++;
78                         }
79
80                         char **env = lua_newuserdata(L, sizeof(char*) * (argn + 1));
81                         env[argn] = NULL;
82
83                         for (i = 1; i < argn; i++) {
84                                 env[i-1] = (char *)lua_tostring(L, -i);
85                         }
86
87                         execve(path, args, env);
88                 }
89         } else {
90                 for (i = 2; i <= argn; i++) {
91                         arg = luaL_checkstring(L, i);
92                         args[i-1] = (char *)arg;
93                 }
94
95                 if (m == NIXIO_EXECV) {
96                         execv(path, args);
97                 } else {
98                         execvp(path, args);
99                 }
100         }
101
102         return nixio__perror(L);
103 }
104
105 #ifndef __WINNT__
106 #include <sys/utsname.h>
107 #include <sys/times.h>
108 #include <sys/wait.h>
109 #include <pwd.h>
110 #include <grp.h>
111
112 static int nixio_fork(lua_State *L) {
113         pid_t pid = fork();
114         if (pid == -1) {
115                 return nixio__perror(L);
116         } else {
117                 lua_pushinteger(L, pid);
118                 return 1;
119         }
120 }
121
122 static int nixio_kill(lua_State *L) {
123         return nixio__pstatus(L, !kill(luaL_checkint(L, 1), luaL_checkint(L, 2)));
124 }
125
126 static int nixio_getppid(lua_State *L) {
127         lua_pushinteger(L, getppid());
128         return 1;
129 }
130
131 static int nixio_getuid(lua_State *L) {
132         lua_pushinteger(L, getuid());
133         return 1;
134 }
135
136 static int nixio_getgid(lua_State *L) {
137         lua_pushinteger(L, getgid());
138         return 1;
139 }
140
141 static int nixio_setgid(lua_State *L) {
142         return nixio__pstatus(L, !setgid(nixio__check_group(L, 1)));
143 }
144
145 static int nixio_setuid(lua_State *L) {
146         return nixio__pstatus(L, !setuid(nixio__check_user(L, 1)));
147 }
148
149 static int nixio_nice(lua_State *L) {
150         int nval = luaL_checkint(L, 1);
151
152         errno = 0;
153         nval = nice(nval);
154
155         if (nval == -1 && errno) {
156                 return nixio__perror(L);
157         } else {
158                 lua_pushinteger(L, nval);
159                 return 1;
160         }
161 }
162
163 static int nixio_setsid(lua_State *L) {
164         pid_t pid = setsid();
165
166         if (pid == -1) {
167                 return nixio__perror(L);
168         } else {
169                 lua_pushinteger(L, pid);
170                 return 1;
171         }
172 }
173
174 static int nixio_wait(lua_State *L) {
175         pid_t pidin = luaL_optinteger(L, 1, -1), pidout;
176         int options = 0, status;
177
178         const int j = lua_gettop(L);
179         for (int i=2; i<=j; i++) {
180                 const char *flag = luaL_checkstring(L, i);
181                 if (!strcmp(flag, "nohang")) {
182                         options |= WNOHANG;
183                 } else if (!strcmp(flag, "untraced")) {
184                         options |= WUNTRACED;
185                 } else if (!strcmp(flag, "continued")) {
186                         options |= WCONTINUED;
187                 } else {
188                         return luaL_argerror(L, i,
189                                         "supported values: nohang, untraced, continued");
190                 }
191         }
192
193         do {
194                 pidout = waitpid(pidin, &status, options);
195         } while (pidout == -1 && errno == EINTR);
196
197         if (pidout == 0) {
198                 lua_pushboolean(L, 0);
199                 return 1;
200         } else if (pidout == -1) {
201                 return nixio__perror(L);
202         } else {
203                 lua_pushinteger(L, pidout);
204         }
205
206         if (WIFEXITED(status)) {
207                 lua_pushliteral(L, "exited");
208                 lua_pushinteger(L, WEXITSTATUS(status));
209     } else if (WIFSIGNALED(status)) {
210         lua_pushliteral(L, "signaled");
211         lua_pushinteger(L, WTERMSIG(status));
212     } else if (WIFSTOPPED(status)) {
213         lua_pushliteral(L, "stopped");
214         lua_pushinteger(L, WSTOPSIG(status));
215     } else {
216         return 1;
217     }
218
219     return 3;
220 }
221
222 static int nixio_times(lua_State *L) {
223         struct tms buf;
224         if (times(&buf) == -1) {
225                 return nixio__perror(L);
226         } else {
227                 lua_createtable(L, 0, 4);
228                 nixio__pushnumber(L, buf.tms_cstime);
229                 lua_setfield(L, -2, "cstime");
230
231                 nixio__pushnumber(L, buf.tms_cutime);
232                 lua_setfield(L, -2, "cutime");
233
234                 nixio__pushnumber(L, buf.tms_stime);
235                 lua_setfield(L, -2, "stime");
236
237                 nixio__pushnumber(L, buf.tms_utime);
238                 lua_setfield(L, -2, "utime");
239
240                 return 1;
241         }
242 }
243
244 static int nixio_uname(lua_State *L) {
245         struct utsname buf;
246         if (uname(&buf)) {
247                 return nixio__perror(L);
248         }
249
250         lua_createtable(L, 0, 5);
251
252         lua_pushstring(L, buf.machine);
253         lua_setfield(L, -2, "machine");
254
255         lua_pushstring(L, buf.version);
256         lua_setfield(L, -2, "version");
257
258         lua_pushstring(L, buf.release);
259         lua_setfield(L, -2, "release");
260
261         lua_pushstring(L, buf.nodename);
262         lua_setfield(L, -2, "nodename");
263
264         lua_pushstring(L, buf.sysname);
265         lua_setfield(L, -2, "sysname");
266
267         return 1;
268 }
269
270 #endif /* !__WINNT__ */
271
272 static int nixio_chdir(lua_State *L) {
273         return nixio__pstatus(L, !chdir(luaL_checkstring(L, 1)));
274 }
275
276 static int nixio_signal(lua_State *L) {
277         int sig = luaL_checkinteger(L, 1);
278         const char *val = luaL_checkstring(L, 2);
279
280         if (!strcmp(val, "ign") || !strcmp(val, "ignore")) {
281                 return nixio__pstatus(L, signal(sig, SIG_IGN) != SIG_ERR);
282         } else if (!strcmp(val, "dfl") || !strcmp(val, "default")) {
283                 return nixio__pstatus(L, signal(sig, SIG_DFL) != SIG_ERR);
284         } else {
285                 return luaL_argerror(L, 2, "supported values: ign, dfl");
286         }
287 }
288
289 static int nixio_getpid(lua_State *L) {
290         lua_pushinteger(L, getpid());
291         return 1;
292 }
293
294 static int nixio_getenv(lua_State *L) {
295         const char *key = luaL_optstring(L, 1, NULL);
296         if (key) {
297                 const char *val = getenv(key);
298                 if (val) {
299                         lua_pushstring(L, val);
300                 } else {
301                         lua_pushnil(L);
302                 }
303         } else {
304                 lua_newtable(L);
305                 extern char **environ;
306                 for (char **c = environ; *c; c++) {
307                         const char *delim = strchr(*c, '=');
308                         if (!delim) {
309                                 return luaL_error(L, "invalid environment");
310                         }
311                         lua_pushlstring(L, *c, delim-*c);
312                         lua_pushstring(L, delim + 1);
313                         lua_rawset(L, -3);
314                 }
315         }
316         return 1;
317 }
318
319 static int nixio_setenv(lua_State *L) {
320         const char *key = luaL_checkstring(L, 1);
321         const char *val = luaL_optstring(L, 2, NULL);
322         return nixio__pstatus(L, (val) ? !setenv(key, val, 1) : !unsetenv(key));
323 }
324
325 static int nixio_exec(lua_State *L) {
326         return nixio__exec(L, NIXIO_EXECV);
327 }
328
329 static int nixio_execp(lua_State *L) {
330         return nixio__exec(L, NIXIO_EXECVP);
331 }
332
333 static int nixio_exece(lua_State *L) {
334         return nixio__exec(L, NIXIO_EXECVE);
335 }
336
337 static int nixio_getcwd(lua_State *L) {
338         char path[PATH_MAX];
339
340         if (getcwd(path, sizeof(path))) {
341                 lua_pushstring(L, path);
342                 return 1;
343         } else {
344                 return nixio__perror(L);
345         }
346 }
347
348 static int nixio_umask(lua_State *L) {
349         char mask[9];
350         lua_pushinteger(L,
351                         nixio__mode_write(umask(nixio__check_mode(L, 1, -1)), mask));
352         lua_pushlstring(L, mask, 9);
353         return 2;
354 }
355
356 #ifdef __linux__
357
358 #include <sys/sysinfo.h>
359
360 static int nixio_sysinfo(lua_State *L) {
361         struct sysinfo info;
362         if (sysinfo(&info)) {
363                 return nixio__perror(L);
364         }
365
366         lua_createtable(L, 0, 12);
367
368         nixio__pushnumber(L, info.bufferram);
369         lua_setfield(L, -2, "bufferram");
370
371         nixio__pushnumber(L, info.freehigh);
372         lua_setfield(L, -2, "freehigh");
373
374         nixio__pushnumber(L, info.freeram);
375         lua_setfield(L, -2, "freeram");
376
377         nixio__pushnumber(L, info.freeswap);
378         lua_setfield(L, -2, "freeswap");
379
380         lua_createtable(L, 0, 3);
381         for (int i=0; i<3; i++) {
382                 lua_pushnumber(L, info.loads[i] / 65536.);
383                 lua_rawseti(L, -2, i+1);
384         }
385         lua_setfield(L, -2, "loads");
386
387         lua_pushinteger(L, info.mem_unit);
388         lua_setfield(L, -2, "mem_unit");
389
390         lua_pushinteger(L, info.procs);
391         lua_setfield(L, -2, "procs");
392
393         nixio__pushnumber(L, info.sharedram);
394         lua_setfield(L, -2, "sharedram");
395
396         nixio__pushnumber(L, info.totalhigh);
397         lua_setfield(L, -2, "totalhigh");
398
399         nixio__pushnumber(L, info.totalram);
400         lua_setfield(L, -2, "totalram");
401
402         nixio__pushnumber(L, info.totalswap);
403         lua_setfield(L, -2, "totalswap");
404
405         lua_pushinteger(L, info.uptime);
406         lua_setfield(L, -2, "uptime");
407
408         return 1;
409 }
410
411 #endif
412
413
414 /* module table */
415 static const luaL_reg R[] = {
416 #ifdef __linux__
417         {"sysinfo",             nixio_sysinfo},
418 #endif
419 #ifndef __WINNT__
420         {"fork",                nixio_fork},
421         {"kill",                nixio_kill},
422         {"nice",                nixio_nice},
423         {"getppid",             nixio_getppid},
424         {"getuid",              nixio_getuid},
425         {"getgid",              nixio_getgid},
426         {"setuid",              nixio_setuid},
427         {"setgid",              nixio_setgid},
428         {"setsid",              nixio_setsid},
429         {"wait",                nixio_wait},
430         {"waitpid",             nixio_wait},
431         {"times",               nixio_times},
432         {"uname",               nixio_uname},
433 #endif
434         {"chdir",               nixio_chdir},
435         {"signal",              nixio_signal},
436         {"getpid",              nixio_getpid},
437         {"getenv",              nixio_getenv},
438         {"setenv",              nixio_setenv},
439         {"putenv",              nixio_setenv},
440         {"exec",                nixio_exec},
441         {"execp",               nixio_execp},
442         {"exece",               nixio_exece},
443         {"getcwd",              nixio_getcwd},
444         {"umask",               nixio_umask},
445         {NULL,                  NULL}
446 };
447
448 void nixio_open_process(lua_State *L) {
449         luaL_register(L, NULL, R);
450 }