/* * lposix.c * POSIX library for Lua 5.1. * Luiz Henrique de Figueiredo * 07 Apr 2006 23:17:49 * Clean up and bug fixes by Leo Razoumov 2006-10-11 * Based on original by Claudio Terra for Lua 3.x. * With contributions by Roberto Ierusalimschy. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MYNAME "posix" #define MYVERSION MYNAME " library for " LUA_VERSION " / Jan 2008" #ifndef ENABLE_SYSLOG #define ENABLE_SYSLOG 1 #endif #include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "modemuncher.h" /* compatibility with Lua 5.0 */ #ifndef LUA_VERSION_NUM static int luaL_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) { const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg); int i = luaL_findstring(name, lst); if (i == -1) luaL_argerror(L, narg, lua_pushfstring(L, "invalid option '%s'", name)); return i; } #define lua_pushinteger lua_pushnumber #define lua_createtable(L,a,r) lua_newtable(L) #define LUA_FILEHANDLE "FILE*" #define lua_setfield(l,i,k) #define lua_getfield(l,i,k) #endif static const struct { char c; mode_t b; } M[] = { {'r', S_IRUSR}, {'w', S_IWUSR}, {'x', S_IXUSR}, {'r', S_IRGRP}, {'w', S_IWGRP}, {'x', S_IXGRP}, {'r', S_IROTH}, {'w', S_IWOTH}, {'x', S_IXOTH}, }; static void pushmode(lua_State *L, mode_t mode) { char m[9]; int i; for (i=0; i<9; i++) m[i]= (mode & M[i].b) ? M[i].c : '-'; if (mode & S_ISUID) m[2]= (mode & S_IXUSR) ? 's' : 'S'; if (mode & S_ISGID) m[5]= (mode & S_IXGRP) ? 's' : 'S'; lua_pushlstring(L, m, 9); } typedef void (*Selector)(lua_State *L, int i, const void *data); static int doselection(lua_State *L, int i, int n, const char *const S[], Selector F, const void *data) { if (lua_isnone(L, i) || lua_istable(L, i)) { int j; if (lua_isnone(L, i)) lua_createtable(L,0,n); else lua_settop(L, i); for (j=0; S[j]!=NULL; j++) { lua_pushstring(L, S[j]); F(L, j, data); lua_settable(L, -3); } return 1; } else { int k,n=lua_gettop(L); for (k=i; k<=n; k++) { int j=luaL_checkoption(L, k, NULL, S); F(L, j, data); lua_replace(L, k); } return n-i+1; } } #define doselection(L,i,S,F,d) (doselection)(L,i,sizeof(S)/sizeof(*S)-1,S,F,d) static int pusherror(lua_State *L, const char *info) { lua_pushnil(L); if (info==NULL) lua_pushstring(L, strerror(errno)); else lua_pushfstring(L, "%s: %s", info, strerror(errno)); lua_pushinteger(L, errno); return 3; } static int pushresult(lua_State *L, int i, const char *info) { if (i==-1) return pusherror(L, info); lua_pushinteger(L, i); return 1; } static void badoption(lua_State *L, int i, const char *what, int option) { luaL_argerror(L, 2, lua_pushfstring(L, "unknown %s option '%c'", what, option)); } static uid_t mygetuid(lua_State *L, int i) { if (lua_isnone(L, i)) return -1; else if (lua_isnumber(L, i)) return (uid_t) lua_tonumber(L, i); else if (lua_isstring(L, i)) { struct passwd *p=getpwnam(lua_tostring(L, i)); return (p==NULL) ? -1 : p->pw_uid; } else return luaL_typerror(L, i, "string or number"); } static gid_t mygetgid(lua_State *L, int i) { if (lua_isnone(L, i)) return -1; else if (lua_isnumber(L, i)) return (gid_t) lua_tonumber(L, i); else if (lua_isstring(L, i)) { struct group *g=getgrnam(lua_tostring(L, i)); return (g==NULL) ? -1 : g->gr_gid; } else return luaL_typerror(L, i, "string or number"); } static int Perrno(lua_State *L) /** errno([n]) */ { int n = luaL_optint(L, 1, errno); lua_pushstring(L, strerror(n)); lua_pushinteger(L, n); return 2; } static int Pbasename(lua_State *L) /** basename(path) */ { char b[PATH_MAX]; size_t len; const char *path = luaL_checklstring(L, 1, &len); if (len>=sizeof(b)) luaL_argerror(L, 1, "too long"); lua_pushstring(L, basename(strcpy(b,path))); return 1; } static int Pdirname(lua_State *L) /** dirname(path) */ { char b[PATH_MAX]; size_t len; const char *path = luaL_checklstring(L, 1, &len); if (len>=sizeof(b)) luaL_argerror(L, 1, "too long"); lua_pushstring(L, dirname(strcpy(b,path))); return 1; } static int Pdir(lua_State *L) /** dir([path]) */ { const char *path = luaL_optstring(L, 1, "."); DIR *d = opendir(path); if (d == NULL) return pusherror(L, path); else { int i; struct dirent *entry; lua_newtable(L); for (i=1; (entry = readdir(d)) != NULL; i++) { lua_pushstring(L, entry->d_name); lua_rawseti(L, -2, i); } closedir(d); lua_pushinteger(L, i-1); return 2; } } static int Pglob(lua_State *L) /** glob(pattern) */ { const char *pattern = luaL_optstring(L, 1, "*"); glob_t globres; if (glob(pattern, 0, NULL, &globres)) return pusherror(L, pattern); else { int i; lua_newtable(L); for (i=1; i<=globres.gl_pathc; i++) { lua_pushstring(L, globres.gl_pathv[i-1]); lua_rawseti(L, -2, i); } globfree(&globres); return 1; } } static int aux_files(lua_State *L) { DIR **p = (DIR **)lua_touserdata(L, lua_upvalueindex(1)); DIR *d = *p; struct dirent *entry; if (d == NULL) return 0; entry = readdir(d); if (entry == NULL) { closedir(d); *p=NULL; return 0; } else { lua_pushstring(L, entry->d_name); return 1; } } static int dir_gc (lua_State *L) { DIR *d = *(DIR **)lua_touserdata(L, 1); if (d!=NULL) closedir(d); return 0; } static int Pfiles(lua_State *L) /** files([path]) */ { const char *path = luaL_optstring(L, 1, "."); DIR **d = (DIR **)lua_newuserdata(L, sizeof(DIR *)); if (luaL_newmetatable(L, MYNAME " dir handle")) { lua_pushliteral(L, "__gc"); lua_pushcfunction(L, dir_gc); lua_settable(L, -3); } lua_setmetatable(L, -2); *d = opendir(path); if (*d == NULL) return pusherror(L, path); lua_pushcclosure(L, aux_files, 1); return 1; } static int Pgetcwd(lua_State *L) /** getcwd() */ { char b[PATH_MAX]; if (getcwd(b, sizeof(b)) == NULL) return pusherror(L, "."); lua_pushstring(L, b); return 1; } static int Pmkdir(lua_State *L) /** mkdir(path) */ { const char *path = luaL_checkstring(L, 1); return pushresult(L, mkdir(path, 0777), path); } static int Pchdir(lua_State *L) /** chdir(path) */ { const char *path = luaL_checkstring(L, 1); return pushresult(L, chdir(path), path); } static int Prmdir(lua_State *L) /** rmdir(path) */ { const char *path = luaL_checkstring(L, 1); return pushresult(L, rmdir(path), path); } static int Punlink(lua_State *L) /** unlink(path) */ { const char *path = luaL_checkstring(L, 1); return pushresult(L, unlink(path), path); } static int Plink(lua_State *L) /** link(old,new,[symbolic]) */ { const char *oldpath = luaL_checkstring(L, 1); const char *newpath = luaL_checkstring(L, 2); return pushresult(L, (lua_toboolean(L,3) ? symlink : link)(oldpath, newpath), NULL); } static int Preadlink(lua_State *L) /** readlink(path) */ { char b[PATH_MAX]; const char *path = luaL_checkstring(L, 1); int n = readlink(path, b, sizeof(b)); if (n==-1) return pusherror(L, path); lua_pushlstring(L, b, n); return 1; } static int Paccess(lua_State *L) /** access(path,[mode]) */ { int mode=F_OK; const char *path=luaL_checkstring(L, 1); const char *s; for (s=luaL_optstring(L, 2, "f"); *s!=0 ; s++) switch (*s) { case ' ': break; case 'r': mode |= R_OK; break; case 'w': mode |= W_OK; break; case 'x': mode |= X_OK; break; case 'f': mode |= F_OK; break; default: badoption(L, 2, "mode", *s); break; } return pushresult(L, access(path, mode), path); } static int myfclose (lua_State *L) { FILE **p = (FILE **)lua_touserdata(L, 1); int rc = fclose(*p); if (rc == 0) *p = NULL; return pushresult(L, rc, NULL); } static int pushfile (lua_State *L, int id, const char *mode) { FILE **f = (FILE **)lua_newuserdata(L, sizeof(FILE *)); *f = NULL; luaL_getmetatable(L, LUA_FILEHANDLE); lua_setmetatable(L, -2); lua_getfield(L, LUA_REGISTRYINDEX, "POSIX_PIPEFILE"); if (lua_isnil(L, -1)) { lua_pop(L, 1); lua_newtable(L); lua_pushvalue(L, -1); lua_pushcfunction(L, myfclose); lua_setfield(L, -2, "__close"); lua_setfield(L, LUA_REGISTRYINDEX, "POSIX_PIPEFILE"); } lua_setfenv(L, -2); *f = fdopen(id, mode); return (*f != NULL); } static int Ppipe(lua_State *L) /** pipe() */ { int fd[2]; if (pipe(fd)==-1) return pusherror(L, NULL); if (!pushfile(L, fd[0], "r") || !pushfile(L, fd[1], "w")) return pusherror(L, "pipe"); return 2; } static int Pfileno(lua_State *L) /** fileno(filehandle) */ { FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE); return pushresult(L, fileno(f), NULL); } static int Pfdopen(lua_State *L) /** fdopen(fd, mode) */ { int fd = luaL_checkint(L, 1); const char *mode = luaL_checkstring(L, 2); if (!pushfile(L, fd, mode)) return pusherror(L, "fdpoen"); return 1; } /* helper func for Pdup */ static const char *filemode(int fd) { const char *m; int mode = fcntl(fd, F_GETFL); if (mode < 0) return NULL; switch (mode & O_ACCMODE) { case O_RDONLY: m = "r"; break; case O_WRONLY: m = "w"; break; default: m = "rw"; break; } return m; } static int Pdup(lua_State *L) /** dup(old,[new]) */ { FILE **oldf = (FILE**)luaL_checkudata(L, 1, LUA_FILEHANDLE); FILE **newf = (FILE **)lua_touserdata(L, 2); int fd; const char *msg = "dup2"; fflush(*newf); if (newf == NULL) { fd = dup(fileno(*oldf)); msg = "dup"; } else { fflush(*newf); fd = dup2(fileno(*oldf), fileno(*newf)); } if ((fd < 0) || !pushfile(L, fd, filemode(fd))) return pusherror(L, msg); return 1; } static int Pmkfifo(lua_State *L) /** mkfifo(path) */ { const char *path = luaL_checkstring(L, 1); return pushresult(L, mkfifo(path, 0777), path); } static int runexec(lua_State *L, int use_shell) { const char *path = luaL_checkstring(L, 1); int i,n=lua_gettop(L); char **argv = lua_newuserdata(L,(n+1)*sizeof(char*)); argv[0] = (char*)path; for (i=1; i