Index: lua-5.1.4/src/Makefile =================================================================== --- lua-5.1.4.orig/src/Makefile 2008-09-25 12:19:44.000000000 +0200 +++ lua-5.1.4/src/Makefile 2008-09-25 12:20:03.000000000 +0200 @@ -12,7 +12,7 @@ AR= ar rcu RANLIB= ranlib RM= rm -f -LIBS= -lm -lz $(MYLIBS) +LIBS= -lm -lz -lcrypt $(MYLIBS) MYCFLAGS= MYLDFLAGS= @@ -29,7 +29,7 @@ lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ lundump.o lvm.o lzio.o lnum.o LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ - lstrlib.o loadlib.o linit.o + lstrlib.o loadlib.o linit.o lposix.o LUA_T= lua LUA_O= lua.o Index: lua-5.1.4/src/linit.c =================================================================== --- lua-5.1.4.orig/src/linit.c 2008-09-25 12:19:02.000000000 +0200 +++ lua-5.1.4/src/linit.c 2008-09-25 12:19:32.000000000 +0200 @@ -23,6 +23,7 @@ {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, + {LUA_POSIXLIBNAME, luaopen_posix}, {NULL, NULL} }; Index: lua-5.1.4/src/lposix.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ lua-5.1.4/src/lposix.c 2008-09-25 12:16:29.000000000 +0200 @@ -0,0 +1,1139 @@ +/* +* 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.c" + +/* 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 POSIX constant lookup tables */ +struct modeLookup +{ + char rwx; + mode_t bits; +}; + +typedef struct modeLookup modeLookup; + +static modeLookup modesel[] = +{ + /* RWX char Posix Constant */ + {'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}, + {0, (mode_t)-1} /* do not delete this line */ +}; + + + +static int rwxrwxrwx(mode_t *mode, const char *p) +{ + int count; + mode_t tmp_mode = *mode; + + tmp_mode &= ~(S_ISUID | S_ISGID); /* turn off suid and sgid flags */ + for (count=0; count<9; count ++) + { + if (*p == modesel[count].rwx) tmp_mode |= modesel[count].bits; /* set a bit */ + else if (*p == '-') tmp_mode &= ~modesel[count].bits; /* clear a bit */ + else if (*p=='s') switch(count) + { + case 2: /* turn on suid flag */ + tmp_mode |= S_ISUID | S_IXUSR; + break; + + case 5: /* turn on sgid flag */ + tmp_mode |= S_ISGID | S_IXGRP; + break; + + default: + return -4; /* failed! -- bad rwxrwxrwx mode change */ + break; + } + p++; + } + *mode = tmp_mode; + return 0; +} + +static void modechopper(mode_t mode, char *p) +{ + /* requires char p[10] */ + int count; + char *pp; + + pp=p; + + for (count=0; count<9; count ++) + { + if (mode & modesel[count].bits) *p = modesel[count].rwx; + else *p='-'; + + p++; + } + *p=0; /* to finish the string */ + + /* dealing with suid and sgid flags */ + if (mode & S_ISUID) pp[2] = (mode & S_IXUSR) ? 's' : 'S'; + if (mode & S_ISGID) pp[5] = (mode & S_IXGRP) ? 's' : 'S'; + +} + +static int mode_munch(mode_t *mode, const char* p) +{ + + char op=0; + mode_t affected_bits, ch_mode; + int doneFlag = 0; +#ifdef DEBUG +char tmp[10]; +#endif + +#ifdef DEBUG +modechopper(*mode, tmp); +printf("modemuncher: got base mode = %s\n", tmp); +#endif + + while (!doneFlag) + { + /* step 0 -- clear temporary variables */ + affected_bits=0; + ch_mode=0; + + /* step 1 -- who's affected? */ + +#ifdef DEBUG +printf("modemuncher step 1\n"); +#endif + + /* mode string given in rwxrwxrwx format */ + if (*p== 'r' || *p == '-') return rwxrwxrwx(mode, p); + + /* mode string given in ugoa+-=rwx format */ + for ( ; ; p++) + switch (*p) + { + case 'u': + affected_bits |= 04700; + break; + + case 'g': + affected_bits |= 02070; + break; + + case 'o': + affected_bits |= 01007; + break; + + case 'a': + affected_bits |= 07777; + break; + + /* ignore spaces */ + case ' ': + break; + + + default: + goto no_more_affected; + } + + no_more_affected: + /* If none specified, affect all bits. */ + if (affected_bits == 0) affected_bits = 07777; + + /* step 2 -- how is it changed? */ + +#ifdef DEBUG +printf("modemuncher step 2 (*p='%c')\n", *p); +#endif + + switch (*p) + { + case '+': + case '-': + case '=': + op = *p; + break; + + /* ignore spaces */ + case ' ': + break; + + default: + return -1; /* failed! -- bad operator */ + } + + + /* step 3 -- what are the changes? */ + +#ifdef DEBUG +printf("modemuncher step 3\n"); +#endif + + for (p++ ; *p!=0 ; p++) + switch (*p) + { + case 'r': + ch_mode |= 00444; + break; + + case 'w': + ch_mode |= 00222; + break; + + case 'x': + ch_mode |= 00111; + break; + + case 's': + /* Set the setuid/gid bits if `u' or `g' is selected. */ + ch_mode |= 06000; + break; + + /* ignore spaces */ + case ' ': + break; + + default: + goto specs_done; + } + + specs_done: + /* step 4 -- apply the changes */ + +#ifdef DEBUG + printf("modemuncher step 4\n"); +#endif + if (*p != ',') doneFlag = 1; + if (*p != 0 && *p != ' ' && *p != ',') + { + +#ifdef DEBUG +printf("modemuncher: comma error!\n"); +printf("modemuncher: doneflag = %u\n", doneFlag); +#endif + return -2; /* failed! -- bad mode change */ + + } + p++; + /*if (!ch_mode) return -2;*/ /* failed! -- bad mode change */ + if (ch_mode) switch (op) + { + case '+': + *mode = *mode |= ch_mode & affected_bits; + break; + + case '-': + *mode = *mode &= ~(ch_mode & affected_bits); + break; + + case '=': + *mode = ch_mode & affected_bits; + break; + + default: + return -3; /* failed! -- unknown error */ + } + } +#ifdef DEBUG +modechopper(*mode, tmp); +printf("modemuncher: returning mode = %s\n", tmp); +#endif + + return 0; /* successful call */ +} + +