Rework LuCI build system
[project/luci.git] / libs / luci-lib-nixio / src / process.c
diff --git a/libs/luci-lib-nixio/src/process.c b/libs/luci-lib-nixio/src/process.c
new file mode 100644 (file)
index 0000000..5ae9b82
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * nixio - Linux I/O library for lua
+ *
+ *   Copyright (C) 2009 Steven Barth <steven@midlink.org>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include "nixio.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#define NIXIO_EXECVE   0x01
+#define NIXIO_EXECV            0x02
+#define NIXIO_EXECVP   0x03
+
+int nixio__exec(lua_State *L, int m) {
+       const char *path = luaL_checkstring(L, 1);
+       const char *arg;
+       int argn, i;
+
+       if (m == NIXIO_EXECVE) {
+               luaL_checktype(L, 2, LUA_TTABLE);
+               argn = lua_objlen(L, 2) + 1;
+       } else {
+               argn = lua_gettop(L);
+       }
+
+       char **args = lua_newuserdata(L, sizeof(char*) * (argn + 1));
+       args[argn] = NULL;
+       args[0] = (char *)path;
+
+       if (m == NIXIO_EXECVE) {
+               for (i = 1; i < argn; i++) {
+                       lua_rawgeti(L, 2, i);
+                       arg = lua_tostring(L, -1);
+                       luaL_argcheck(L, arg, 2, "invalid argument");
+                       args[i] = (char *)arg;
+               }
+
+               if (lua_isnoneornil(L, 3)) {
+                       execv(path, args);
+               } else {
+                       luaL_checktype(L, 3, LUA_TTABLE);
+                       argn = 0;
+                       lua_pushnil(L);
+                       while (lua_next(L, 3)) {
+                               if (!lua_checkstack(L, 1)) {
+                                       lua_settop(L, 0);
+                                       return luaL_error(L, "stack overflow");
+                               }
+
+                               if (lua_type(L, -2) != LUA_TSTRING || !lua_isstring(L, -1)) {
+                                       return luaL_argerror(L, 3, "invalid environment");
+                               }
+
+                               lua_pushfstring(L, "%s=%s",
+                                               lua_tostring(L, -2), lua_tostring(L, -1));
+
+                               lua_insert(L, 5);
+                               lua_pop(L, 1);
+                               argn++;
+                       }
+
+                       char **env = lua_newuserdata(L, sizeof(char*) * (argn + 1));
+                       env[argn] = NULL;
+
+                       for (i = 1; i <= argn; i++) {
+                               env[i-1] = (char *)lua_tostring(L, -(i+1));
+                       }
+
+                       execve(path, args, env);
+               }
+       } else {
+               for (i = 2; i <= argn; i++) {
+                       arg = luaL_checkstring(L, i);
+                       args[i-1] = (char *)arg;
+               }
+
+               if (m == NIXIO_EXECV) {
+                       execv(path, args);
+               } else {
+                       execvp(path, args);
+               }
+       }
+
+       return nixio__perror(L);
+}
+
+#ifndef __WINNT__
+#include <sys/utsname.h>
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <grp.h>
+
+static int nixio_fork(lua_State *L) {
+       pid_t pid = fork();
+       if (pid == -1) {
+               return nixio__perror(L);
+       } else {
+               lua_pushinteger(L, pid);
+               return 1;
+       }
+}
+
+static int nixio_kill(lua_State *L) {
+       return nixio__pstatus(L, !kill(luaL_checkint(L, 1), luaL_checkint(L, 2)));
+}
+
+static int nixio_getppid(lua_State *L) {
+       lua_pushinteger(L, getppid());
+       return 1;
+}
+
+static int nixio_getuid(lua_State *L) {
+       lua_pushinteger(L, getuid());
+       return 1;
+}
+
+static int nixio_getgid(lua_State *L) {
+       lua_pushinteger(L, getgid());
+       return 1;
+}
+
+static int nixio_setgid(lua_State *L) {
+       return nixio__pstatus(L, !setgid(nixio__check_group(L, 1)));
+}
+
+static int nixio_setuid(lua_State *L) {
+       return nixio__pstatus(L, !setuid(nixio__check_user(L, 1)));
+}
+
+static int nixio_nice(lua_State *L) {
+       int nval = luaL_checkint(L, 1);
+
+       errno = 0;
+       nval = nice(nval);
+
+       if (nval == -1 && errno) {
+               return nixio__perror(L);
+       } else {
+               lua_pushinteger(L, nval);
+               return 1;
+       }
+}
+
+static int nixio_setsid(lua_State *L) {
+       pid_t pid = setsid();
+
+       if (pid == -1) {
+               return nixio__perror(L);
+       } else {
+               lua_pushinteger(L, pid);
+               return 1;
+       }
+}
+
+static int nixio_wait(lua_State *L) {
+       pid_t pidin = luaL_optinteger(L, 1, -1), pidout;
+       int options = 0, status;
+
+       const int j = lua_gettop(L);
+       for (int i=2; i<=j; i++) {
+               const char *flag = luaL_checkstring(L, i);
+               if (!strcmp(flag, "nohang")) {
+                       options |= WNOHANG;
+               } else if (!strcmp(flag, "untraced")) {
+                       options |= WUNTRACED;
+               } else if (!strcmp(flag, "continued")) {
+                       options |= WCONTINUED;
+               } else {
+                       return luaL_argerror(L, i,
+                                       "supported values: nohang, untraced, continued");
+               }
+       }
+
+       do {
+               pidout = waitpid(pidin, &status, options);
+       } while (pidout == -1 && errno == EINTR);
+
+       if (pidout == 0) {
+               lua_pushboolean(L, 0);
+               return 1;
+       } else if (pidout == -1) {
+               return nixio__perror(L);
+       } else {
+               lua_pushinteger(L, pidout);
+       }
+
+       if (WIFEXITED(status)) {
+               lua_pushliteral(L, "exited");
+               lua_pushinteger(L, WEXITSTATUS(status));
+    } else if (WIFSIGNALED(status)) {
+       lua_pushliteral(L, "signaled");
+       lua_pushinteger(L, WTERMSIG(status));
+    } else if (WIFSTOPPED(status)) {
+       lua_pushliteral(L, "stopped");
+       lua_pushinteger(L, WSTOPSIG(status));
+    } else {
+       return 1;
+    }
+
+    return 3;
+}
+
+static int nixio_times(lua_State *L) {
+       struct tms buf;
+       if (times(&buf) == -1) {
+               return nixio__perror(L);
+       } else {
+               lua_createtable(L, 0, 4);
+               nixio__pushnumber(L, buf.tms_cstime);
+               lua_setfield(L, -2, "cstime");
+
+               nixio__pushnumber(L, buf.tms_cutime);
+               lua_setfield(L, -2, "cutime");
+
+               nixio__pushnumber(L, buf.tms_stime);
+               lua_setfield(L, -2, "stime");
+
+               nixio__pushnumber(L, buf.tms_utime);
+               lua_setfield(L, -2, "utime");
+
+               return 1;
+       }
+}
+
+static int nixio_uname(lua_State *L) {
+       struct utsname buf;
+       if (uname(&buf)) {
+               return nixio__perror(L);
+       }
+
+       lua_createtable(L, 0, 5);
+
+       lua_pushstring(L, buf.machine);
+       lua_setfield(L, -2, "machine");
+
+       lua_pushstring(L, buf.version);
+       lua_setfield(L, -2, "version");
+
+       lua_pushstring(L, buf.release);
+       lua_setfield(L, -2, "release");
+
+       lua_pushstring(L, buf.nodename);
+       lua_setfield(L, -2, "nodename");
+
+       lua_pushstring(L, buf.sysname);
+       lua_setfield(L, -2, "sysname");
+
+       return 1;
+}
+
+#endif /* !__WINNT__ */
+
+static int nixio_chdir(lua_State *L) {
+       return nixio__pstatus(L, !chdir(luaL_checkstring(L, 1)));
+}
+
+static int nixio_signal(lua_State *L) {
+       int sig = luaL_checkinteger(L, 1);
+       const char *val = luaL_checkstring(L, 2);
+
+       if (!strcmp(val, "ign") || !strcmp(val, "ignore")) {
+               return nixio__pstatus(L, signal(sig, SIG_IGN) != SIG_ERR);
+       } else if (!strcmp(val, "dfl") || !strcmp(val, "default")) {
+               return nixio__pstatus(L, signal(sig, SIG_DFL) != SIG_ERR);
+       } else {
+               return luaL_argerror(L, 2, "supported values: ign, dfl");
+       }
+}
+
+static int nixio_getpid(lua_State *L) {
+       lua_pushinteger(L, getpid());
+       return 1;
+}
+
+static int nixio_getenv(lua_State *L) {
+       const char *key = luaL_optstring(L, 1, NULL);
+       if (key) {
+               const char *val = getenv(key);
+               if (val) {
+                       lua_pushstring(L, val);
+               } else {
+                       lua_pushnil(L);
+               }
+       } else {
+               lua_newtable(L);
+               extern char **environ;
+               for (char **c = environ; *c; c++) {
+                       const char *delim = strchr(*c, '=');
+                       if (!delim) {
+                               return luaL_error(L, "invalid environment");
+                       }
+                       lua_pushlstring(L, *c, delim-*c);
+                       lua_pushstring(L, delim + 1);
+                       lua_rawset(L, -3);
+               }
+       }
+       return 1;
+}
+
+static int nixio_setenv(lua_State *L) {
+       const char *key = luaL_checkstring(L, 1);
+       const char *val = luaL_optstring(L, 2, NULL);
+       return nixio__pstatus(L, (val) ? !setenv(key, val, 1) : !unsetenv(key));
+}
+
+static int nixio_exec(lua_State *L) {
+       return nixio__exec(L, NIXIO_EXECV);
+}
+
+static int nixio_execp(lua_State *L) {
+       return nixio__exec(L, NIXIO_EXECVP);
+}
+
+static int nixio_exece(lua_State *L) {
+       return nixio__exec(L, NIXIO_EXECVE);
+}
+
+static int nixio_getcwd(lua_State *L) {
+       char path[PATH_MAX];
+
+       if (getcwd(path, sizeof(path))) {
+               lua_pushstring(L, path);
+               return 1;
+       } else {
+               return nixio__perror(L);
+       }
+}
+
+static int nixio_umask(lua_State *L) {
+       char mask[9];
+       lua_pushinteger(L,
+                       nixio__mode_write(umask(nixio__check_mode(L, 1, -1)), mask));
+       lua_pushlstring(L, mask, 9);
+       return 2;
+}
+
+#ifdef __linux__
+
+#include <sys/sysinfo.h>
+
+static int nixio_sysinfo(lua_State *L) {
+       struct sysinfo info;
+       if (sysinfo(&info)) {
+               return nixio__perror(L);
+       }
+
+       lua_createtable(L, 0, 12);
+
+       nixio__pushnumber(L, info.bufferram);
+       lua_setfield(L, -2, "bufferram");
+
+       nixio__pushnumber(L, info.freehigh);
+       lua_setfield(L, -2, "freehigh");
+
+       nixio__pushnumber(L, info.freeram);
+       lua_setfield(L, -2, "freeram");
+
+       nixio__pushnumber(L, info.freeswap);
+       lua_setfield(L, -2, "freeswap");
+
+       lua_createtable(L, 0, 3);
+       for (int i=0; i<3; i++) {
+               lua_pushnumber(L, info.loads[i] / 65536.);
+               lua_rawseti(L, -2, i+1);
+       }
+       lua_setfield(L, -2, "loads");
+
+       lua_pushinteger(L, info.mem_unit);
+       lua_setfield(L, -2, "mem_unit");
+
+       lua_pushinteger(L, info.procs);
+       lua_setfield(L, -2, "procs");
+
+       nixio__pushnumber(L, info.sharedram);
+       lua_setfield(L, -2, "sharedram");
+
+       nixio__pushnumber(L, info.totalhigh);
+       lua_setfield(L, -2, "totalhigh");
+
+       nixio__pushnumber(L, info.totalram);
+       lua_setfield(L, -2, "totalram");
+
+       nixio__pushnumber(L, info.totalswap);
+       lua_setfield(L, -2, "totalswap");
+
+       lua_pushinteger(L, info.uptime);
+       lua_setfield(L, -2, "uptime");
+
+       return 1;
+}
+
+#endif
+
+
+/* module table */
+static const luaL_reg R[] = {
+#ifdef __linux__
+       {"sysinfo",             nixio_sysinfo},
+#endif
+#ifndef __WINNT__
+       {"fork",                nixio_fork},
+       {"kill",                nixio_kill},
+       {"nice",                nixio_nice},
+       {"getppid",             nixio_getppid},
+       {"getuid",              nixio_getuid},
+       {"getgid",              nixio_getgid},
+       {"setuid",              nixio_setuid},
+       {"setgid",              nixio_setgid},
+       {"setsid",              nixio_setsid},
+       {"wait",                nixio_wait},
+       {"waitpid",             nixio_wait},
+       {"times",               nixio_times},
+       {"uname",               nixio_uname},
+#endif
+       {"chdir",               nixio_chdir},
+       {"signal",              nixio_signal},
+       {"getpid",              nixio_getpid},
+       {"getenv",              nixio_getenv},
+       {"setenv",              nixio_setenv},
+       {"putenv",              nixio_setenv},
+       {"exec",                nixio_exec},
+       {"execp",               nixio_execp},
+       {"exece",               nixio_exece},
+       {"getcwd",              nixio_getcwd},
+       {"umask",               nixio_umask},
+       {NULL,                  NULL}
+};
+
+void nixio_open_process(lua_State *L) {
+       luaL_register(L, NULL, R);
+}