csomh / source-git / rpm

Forked from source-git/rpm 4 years ago
Clone
2ff057
/*
2ff057
* lposix.c
2ff057
* POSIX library for Lua 5.0. Based on original by Claudio Terra for Lua 3.x.
2ff057
* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
2ff057
* 05 Nov 2003 22:09:10
2ff057
*/
2ff057
2ff057
#ifdef HAVE_CONFIG_H
2ff057
#include <config.h>
2ff057
#endif
2ff057
2ff057
#include <dirent.h>
2ff057
#include <errno.h>
2ff057
#include <fcntl.h>
2ff057
#include <grp.h>
2ff057
#include <pwd.h>
2ff057
#include <signal.h>
2ff057
#include <stdio.h>
2ff057
#include <stdlib.h>
2ff057
#include <string.h>
2ff057
#include <sys/stat.h>
2ff057
#include <sys/times.h>
2ff057
#include <sys/types.h>
2ff057
#include <sys/utsname.h>
2ff057
#include <sys/wait.h>
2ff057
#include <time.h>
2ff057
#include <unistd.h>
2ff057
#include <utime.h>
2ff057
#include <rpm/rpmutil.h>
2ff057
#include "rpmio/rpmio_internal.h"
2ff057
2ff057
#define MYNAME		"posix"
2ff057
#define MYVERSION	MYNAME " library for " LUA_VERSION " / Nov 2003"
2ff057
2ff057
#include "lua.h"
2ff057
#include "lauxlib.h"
2ff057
#include "lposix.h"
2ff057
2ff057
2ff057
#ifndef MYBUFSIZ
2ff057
#define MYBUFSIZ 512
2ff057
#endif
2ff057
2ff057
#include "modemuncher.c"
2ff057
2ff057
static int have_forked = 0;
2ff057
2ff057
static const char *filetype(mode_t m)
2ff057
{
2ff057
	if (S_ISREG(m))		return "regular";
2ff057
	else if (S_ISLNK(m))	return "link";
2ff057
	else if (S_ISDIR(m))	return "directory";
2ff057
	else if (S_ISCHR(m))	return "character device";
2ff057
	else if (S_ISBLK(m))	return "block device";
2ff057
	else if (S_ISFIFO(m))	return "fifo";
2ff057
	else if (S_ISSOCK(m))	return "socket";
2ff057
	else			return "?";
2ff057
}
2ff057
2ff057
typedef int (*Selector)(lua_State *L, int i, const void *data);
2ff057
2ff057
/* implemented as luaL_typerror until lua 5.1, dropped in 5.2
2ff057
 * (C) 1994-2012 Lua.org, PUC-Rio. MIT license
2ff057
 */
2ff057
static int typerror (lua_State *L, int narg, const char *tname) {
2ff057
	const char *msg = lua_pushfstring(L, "%s expected, got %s",
2ff057
					  tname, luaL_typename(L, narg));
2ff057
	return luaL_argerror(L, narg, msg);
2ff057
}
2ff057
2ff057
static int doselection(lua_State *L, int i, const char *const S[], Selector F, const void *data)
2ff057
{
2ff057
	if (lua_isnone(L, i))
2ff057
	{
2ff057
		lua_newtable(L);
2ff057
		for (i=0; S[i]!=NULL; i++)
2ff057
		{
2ff057
			lua_pushstring(L, S[i]);
2ff057
			F(L, i, data);
2ff057
			lua_settable(L, -3);
2ff057
		}
2ff057
		return 1;
2ff057
	}
2ff057
	else
2ff057
	{
2ff057
		int j=luaL_checkoption(L, i, NULL, S);
2ff057
		if (j==-1) luaL_argerror(L, i, "unknown selector");
2ff057
		return F(L, j, data);
2ff057
	}
2ff057
}
2ff057
2ff057
static void storeindex(lua_State *L, int i, const char *value)
2ff057
{
2ff057
	lua_pushstring(L, value);
2ff057
	lua_rawseti(L, -2, i);
2ff057
}
2ff057
2ff057
static void storestring(lua_State *L, const char *name, const char *value)
2ff057
{
2ff057
	lua_pushstring(L, name);
2ff057
	lua_pushstring(L, value);
2ff057
	lua_settable(L, -3);
2ff057
}
2ff057
2ff057
static void storenumber(lua_State *L, const char *name, lua_Number value)
2ff057
{
2ff057
	lua_pushstring(L, name);
2ff057
	lua_pushnumber(L, value);
2ff057
	lua_settable(L, -3);
2ff057
}
2ff057
2ff057
static int pusherror(lua_State *L, const char *info)
2ff057
{
2ff057
	lua_pushnil(L);
2ff057
	if (info==NULL)
2ff057
		lua_pushstring(L, strerror(errno));
2ff057
	else
2ff057
		lua_pushfstring(L, "%s: %s", info, strerror(errno));
2ff057
	lua_pushnumber(L, errno);
2ff057
	return 3;
2ff057
}
2ff057
2ff057
static int pushresult(lua_State *L, int i, const char *info)
2ff057
{
2ff057
	if (i != -1)
2ff057
	{
2ff057
		lua_pushnumber(L, i);
2ff057
		return 1;
2ff057
	}
2ff057
	else
2ff057
		return pusherror(L, info);
2ff057
}
2ff057
2ff057
static void badoption(lua_State *L, int i, const char *what, int option)
2ff057
{
2ff057
	luaL_argerror(L, 2,
2ff057
		lua_pushfstring(L, "unknown %s option `%c'", what, option));
2ff057
}
2ff057
2ff057
static uid_t mygetuid(lua_State *L, int i)
2ff057
{
2ff057
	if (lua_isnone(L, i))
2ff057
		return -1;
2ff057
	else if (lua_isnumber(L, i))
2ff057
		return (uid_t) lua_tonumber(L, i);
2ff057
	else if (lua_isstring(L, i))
2ff057
	{
2ff057
		struct passwd *p=getpwnam(lua_tostring(L, i));
2ff057
		return (p==NULL) ? -1 : p->pw_uid;
2ff057
	}
2ff057
	else
2ff057
		return typerror(L, i, "string or number");
2ff057
}
2ff057
2ff057
static gid_t mygetgid(lua_State *L, int i)
2ff057
{
2ff057
	if (lua_isnone(L, i))
2ff057
		return -1;
2ff057
	else if (lua_isnumber(L, i))
2ff057
		return (gid_t) lua_tonumber(L, i);
2ff057
	else if (lua_isstring(L, i))
2ff057
	{
2ff057
		struct group *g=getgrnam(lua_tostring(L, i));
2ff057
		return (g==NULL) ? -1 : g->gr_gid;
2ff057
	}
2ff057
	else
2ff057
		return typerror(L, i, "string or number");
2ff057
}
2ff057
2ff057
2ff057
2ff057
static int Perrno(lua_State *L)			/** errno() */
2ff057
{
2ff057
	lua_pushstring(L, strerror(errno));
2ff057
	lua_pushnumber(L, errno);
2ff057
	return 2;
2ff057
}
2ff057
2ff057
2ff057
static int Pdir(lua_State *L)			/** dir([path]) */
2ff057
{
2ff057
	const char *path = luaL_optstring(L, 1, ".");
2ff057
	DIR *d = opendir(path);
2ff057
	if (d == NULL)
2ff057
		return pusherror(L, path);
2ff057
	else
2ff057
	{
2ff057
		int i;
2ff057
		struct dirent *entry;
2ff057
		lua_newtable(L);
2ff057
		for (i=1; (entry = readdir(d)) != NULL; i++)
2ff057
			storeindex(L, i, entry->d_name);
2ff057
		closedir(d);
2ff057
		return 1;
2ff057
	}
2ff057
}
2ff057
2ff057
2ff057
static int aux_files(lua_State *L)
2ff057
{
2ff057
	DIR *d = lua_touserdata(L, lua_upvalueindex(1));
2ff057
	struct dirent *entry;
2ff057
	if (d == NULL) return luaL_error(L, "attempt to use closed dir");
2ff057
	entry = readdir(d);
2ff057
	if (entry == NULL)
2ff057
	{
2ff057
		closedir(d);
2ff057
		lua_pushnil(L);
2ff057
		lua_replace(L, lua_upvalueindex(1));
2ff057
		lua_pushnil(L);
2ff057
	}
2ff057
	else
2ff057
	{
2ff057
		lua_pushstring(L, entry->d_name);
2ff057
#if 0
2ff057
#ifdef _DIRENT_HAVE_D_TYPE
2ff057
		lua_pushstring(L, filetype(DTTOIF(entry->d_type)));
2ff057
		return 2;
2ff057
#endif
2ff057
#endif
2ff057
	}
2ff057
	return 1;
2ff057
}
2ff057
2ff057
static int Pfiles(lua_State *L)			/** files([path]) */
2ff057
{
2ff057
	const char *path = luaL_optstring(L, 1, ".");
2ff057
	DIR *d = opendir(path);
2ff057
	if (d == NULL)
2ff057
		return pusherror(L, path);
2ff057
	else
2ff057
	{
2ff057
		lua_pushlightuserdata(L, d);
2ff057
		lua_pushcclosure(L, aux_files, 1);
2ff057
		return 1;
2ff057
	}
2ff057
}
2ff057
2ff057
2ff057
static int Pgetcwd(lua_State *L)		/** getcwd() */
2ff057
{
2ff057
	char buf[MYBUFSIZ];
2ff057
	if (getcwd(buf, sizeof(buf)) == NULL)
2ff057
		return pusherror(L, ".");
2ff057
	else
2ff057
	{
2ff057
		lua_pushstring(L, buf);
2ff057
		return 1;
2ff057
	}
2ff057
}
2ff057
2ff057
2ff057
static int Pmkdir(lua_State *L)			/** mkdir(path) */
2ff057
{
2ff057
	const char *path = luaL_checkstring(L, 1);
2ff057
	return pushresult(L, mkdir(path, 0777), path);
2ff057
}
2ff057
2ff057
2ff057
static int Pchdir(lua_State *L)			/** chdir(path) */
2ff057
{
2ff057
	const char *path = luaL_checkstring(L, 1);
2ff057
	return pushresult(L, chdir(path), path);
2ff057
}
2ff057
2ff057
2ff057
static int Prmdir(lua_State *L)			/** rmdir(path) */
2ff057
{
2ff057
	const char *path = luaL_checkstring(L, 1);
2ff057
	return pushresult(L, rmdir(path), path);
2ff057
}
2ff057
2ff057
2ff057
static int Punlink(lua_State *L)		/** unlink(path) */
2ff057
{
2ff057
	const char *path = luaL_checkstring(L, 1);
2ff057
	return pushresult(L, unlink(path), path);
2ff057
}
2ff057
2ff057
2ff057
static int Plink(lua_State *L)			/** link(oldpath,newpath) */
2ff057
{
2ff057
	const char *oldpath = luaL_checkstring(L, 1);
2ff057
	const char *newpath = luaL_checkstring(L, 2);
2ff057
	return pushresult(L, link(oldpath, newpath), NULL);
2ff057
}
2ff057
2ff057
2ff057
static int Psymlink(lua_State *L)		/** symlink(oldpath,newpath) */
2ff057
{
2ff057
	const char *oldpath = luaL_checkstring(L, 1);
2ff057
	const char *newpath = luaL_checkstring(L, 2);
2ff057
	return pushresult(L, symlink(oldpath, newpath), NULL);
2ff057
}
2ff057
2ff057
2ff057
static int Preadlink(lua_State *L)		/** readlink(path) */
2ff057
{
2ff057
	char buf[MYBUFSIZ];
2ff057
	const char *path = luaL_checkstring(L, 1);
2ff057
	int n = readlink(path, buf, sizeof(buf));
2ff057
	if (n==-1) return pusherror(L, path);
2ff057
	lua_pushlstring(L, buf, n);
2ff057
	return 1;
2ff057
}
2ff057
2ff057
2ff057
static int Paccess(lua_State *L)		/** access(path,[mode]) */
2ff057
{
2ff057
	int mode=F_OK;
2ff057
	const char *path=luaL_checkstring(L, 1);
2ff057
	const char *s;
2ff057
	for (s=luaL_optstring(L, 2, "f"); *s!=0 ; s++)
2ff057
		switch (*s)
2ff057
		{
2ff057
			case ' ': break;
2ff057
			case 'r': mode |= R_OK; break;
2ff057
			case 'w': mode |= W_OK; break;
2ff057
			case 'x': mode |= X_OK; break;
2ff057
			case 'f': mode |= F_OK; break;
2ff057
			default: badoption(L, 2, "mode", *s); break;
2ff057
		}
2ff057
	return pushresult(L, access(path, mode), path);
2ff057
}
2ff057
2ff057
2ff057
static int Pmkfifo(lua_State *L)		/** mkfifo(path) */
2ff057
{
2ff057
	const char *path = luaL_checkstring(L, 1);
2ff057
	return pushresult(L, mkfifo(path, 0777), path);
2ff057
}
2ff057
2ff057
2ff057
static int Pexec(lua_State *L)			/** exec(path,[args]) */
2ff057
{
2ff057
	const char *path = luaL_checkstring(L, 1);
2ff057
	int i,n=lua_gettop(L);
2ff057
	char **argv;
2ff057
2ff057
	if (!have_forked)
2ff057
	    return luaL_error(L, "exec not permitted in this context");
2ff057
2ff057
	rpmSetCloseOnExec();
2ff057
2ff057
	argv = malloc((n+1)*sizeof(char*));
2ff057
	if (argv==NULL) return luaL_error(L,"not enough memory");
2ff057
	argv[0] = (char*)path;
2ff057
	for (i=1; i
2ff057
	argv[i] = NULL;
2ff057
	execvp(path,argv);
2ff057
	return pusherror(L, path);
2ff057
}
2ff057
2ff057
2ff057
static int Pfork(lua_State *L)			/** fork() */
2ff057
{
2ff057
	pid_t pid = fork();
2ff057
	if (pid == 0) {
2ff057
	    have_forked = 1;
2ff057
	}
2ff057
	return pushresult(L, pid, NULL);
2ff057
}
2ff057
2ff057
2ff057
static int Pwait(lua_State *L)			/** wait([pid]) */
2ff057
{
2ff057
	pid_t pid = luaL_optinteger(L, 1, -1);
2ff057
	return pushresult(L, waitpid(pid, NULL, 0), NULL);
2ff057
}
2ff057
2ff057
2ff057
static int Pkill(lua_State *L)			/** kill(pid,[sig]) */
2ff057
{
2ff057
	pid_t pid = luaL_checkinteger(L, 1);
2ff057
	int sig = luaL_optinteger(L, 2, SIGTERM);
2ff057
	return pushresult(L, kill(pid, sig), NULL);
2ff057
}
2ff057
2ff057
2ff057
static int Psleep(lua_State *L)			/** sleep(seconds) */
2ff057
{
2ff057
	unsigned int seconds = luaL_checkinteger(L, 1);
2ff057
	lua_pushnumber(L, sleep(seconds));
2ff057
	return 1;
2ff057
}
2ff057
2ff057
2ff057
static int Pputenv(lua_State *L)		/** putenv(string) */
2ff057
{
2ff057
#if HAVE_PUTENV
2ff057
	size_t l;
2ff057
	const char *s=luaL_checklstring(L, 1, &l);
2ff057
	char *e=malloc(++l);
2ff057
	return pushresult(L, (e==NULL) ? -1 : putenv(memcpy(e,s,l)), s);
2ff057
#else
2ff057
	return -1;
2ff057
#endif
2ff057
}
2ff057
2ff057
2ff057
static int Psetenv(lua_State *L)		/** setenv(name,value,[over]) */
2ff057
{
2ff057
	const char *name=luaL_checkstring(L, 1);
2ff057
	const char *value=luaL_checkstring(L, 2);
2ff057
	int overwrite=lua_isnoneornil(L, 3) || lua_toboolean(L, 3);
2ff057
	return pushresult(L, setenv(name,value,overwrite), name);
2ff057
}
2ff057
2ff057
2ff057
static int Punsetenv(lua_State *L)		/** unsetenv(name) */
2ff057
{
2ff057
	const char *name=luaL_checkstring(L, 1);
2ff057
	unsetenv(name);
2ff057
	return 0;
2ff057
}
2ff057
2ff057
static int Pgetenv(lua_State *L)		/** getenv([name]) */
2ff057
{
2ff057
	if (lua_isnone(L, 1))
2ff057
	{
2ff057
	#ifdef __APPLE__
2ff057
		#include <crt_externs.h>
2ff057
		#define environ (*_NSGetEnviron())
2ff057
	#else
2ff057
		extern char **environ;
2ff057
	#endif /* __APPLE__ */
2ff057
		char **e;
2ff057
		if (*environ==NULL) lua_pushnil(L); else lua_newtable(L);
2ff057
		for (e=environ; *e!=NULL; e++)
2ff057
		{
2ff057
			char *s=*e;
2ff057
			char *eq=strchr(s, '=');
2ff057
			if (eq==NULL)		/* will this ever happen? */
2ff057
			{
2ff057
				lua_pushstring(L,s);
2ff057
				lua_pushboolean(L,0);
2ff057
			}
2ff057
			else
2ff057
			{
2ff057
				lua_pushlstring(L,s,eq-s);
2ff057
				lua_pushstring(L,eq+1);
2ff057
			}
2ff057
			lua_settable(L,-3);
2ff057
		}
2ff057
	}
2ff057
	else
2ff057
		lua_pushstring(L, getenv(luaL_checkstring(L, 1)));
2ff057
	return 1;
2ff057
}
2ff057
2ff057
2ff057
static int Pumask(lua_State *L)			/** umask([mode]) */
2ff057
{
2ff057
	char m[10];
2ff057
	mode_t mode;
2ff057
	umask(mode=umask(0));
2ff057
	mode=(~mode)&0777;
2ff057
	if (!lua_isnone(L, 1))
2ff057
	{
2ff057
		if (mode_munch(&mode, luaL_checkstring(L, 1)))
2ff057
		{
2ff057
			lua_pushnil(L);
2ff057
			return 1;
2ff057
		}
2ff057
		mode&=0777;
2ff057
		umask(~mode);
2ff057
	}
2ff057
	modechopper(mode, m);
2ff057
	lua_pushstring(L, m);
2ff057
	return 1;
2ff057
}
2ff057
2ff057
2ff057
static int Pchmod(lua_State *L)			/** chmod(path,mode) */
2ff057
{
2ff057
	mode_t mode;
2ff057
	struct stat s;
2ff057
	const char *path = luaL_checkstring(L, 1);
2ff057
	const char *modestr = luaL_checkstring(L, 2);
2ff057
	if (stat(path, &s)) return pusherror(L, path);
2ff057
	mode = s.st_mode;
2ff057
	if (mode_munch(&mode, modestr)) luaL_argerror(L, 2, "bad mode");
2ff057
	return pushresult(L, chmod(path, mode), path);
2ff057
}
2ff057
2ff057
2ff057
static int Pchown(lua_State *L)			/** chown(path,uid,gid) */
2ff057
{
2ff057
	const char *path = luaL_checkstring(L, 1);
2ff057
	uid_t uid = mygetuid(L, 2);
2ff057
	gid_t gid = mygetgid(L, 3);
2ff057
	return pushresult(L, chown(path, uid, gid), path);
2ff057
}
2ff057
2ff057
2ff057
static int Putime(lua_State *L)			/** utime(path,[mtime,atime]) */
2ff057
{
2ff057
	struct utimbuf times;
2ff057
	time_t currtime = time(NULL);
2ff057
	const char *path = luaL_checkstring(L, 1);
2ff057
	times.modtime = luaL_optnumber(L, 2, currtime);
2ff057
	times.actime  = luaL_optnumber(L, 3, currtime);
2ff057
	return pushresult(L, utime(path, &times), path);
2ff057
}
2ff057
2ff057
2ff057
static int FgetID(lua_State *L, int i, const void *data)
2ff057
{
2ff057
	switch (i)
2ff057
	{
2ff057
		case 0:	lua_pushnumber(L, getegid());	break;
2ff057
		case 1:	lua_pushnumber(L, geteuid());	break;
2ff057
		case 2:	lua_pushnumber(L, getgid());	break;
2ff057
		case 3:	lua_pushnumber(L, getuid());	break;
2ff057
		case 4:	lua_pushnumber(L, getpgrp());	break;
2ff057
		case 5:	lua_pushnumber(L, getpid());	break;
2ff057
		case 6:	lua_pushnumber(L, getppid());	break;
2ff057
	}
2ff057
	return 1;
2ff057
}
2ff057
2ff057
static const char *const SgetID[] =
2ff057
{
2ff057
	"egid", "euid", "gid", "uid", "pgrp", "pid", "ppid", NULL
2ff057
};
2ff057
2ff057
static int Pgetprocessid(lua_State *L)		/** getprocessid([selector]) */
2ff057
{
2ff057
	return doselection(L, 1, SgetID, FgetID, NULL);
2ff057
}
2ff057
2ff057
2ff057
static int Pttyname(lua_State *L)		/** ttyname(fd) */
2ff057
{
2ff057
	int fd=luaL_optinteger(L, 1, 0);
2ff057
	lua_pushstring(L, ttyname(fd));
2ff057
	return 1;
2ff057
}
2ff057
2ff057
static int Pctermid(lua_State *L)		/** ctermid() */
2ff057
{
2ff057
	char b[L_ctermid];
2ff057
	lua_pushstring(L, ctermid(b));
2ff057
	return 1;
2ff057
}
2ff057
2ff057
2ff057
static int Pgetlogin(lua_State *L)		/** getlogin() */
2ff057
{
2ff057
	lua_pushstring(L, getlogin());
2ff057
	return 1;
2ff057
}
2ff057
2ff057
2ff057
static int Fgetpasswd(lua_State *L, int i, const void *data)
2ff057
{
2ff057
	const struct passwd *p=data;
2ff057
	switch (i)
2ff057
	{
2ff057
		case 0: lua_pushstring(L, p->pw_name); break;
2ff057
		case 1: lua_pushnumber(L, p->pw_uid); break;
2ff057
		case 2: lua_pushnumber(L, p->pw_gid); break;
2ff057
		case 3: lua_pushstring(L, p->pw_dir); break;
2ff057
		case 4: lua_pushstring(L, p->pw_shell); break;
2ff057
/* not strictly POSIX */
2ff057
		case 5: lua_pushstring(L, p->pw_gecos); break;
2ff057
		case 6: lua_pushstring(L, p->pw_passwd); break;
2ff057
	}
2ff057
	return 1;
2ff057
}
2ff057
2ff057
static const char *const Sgetpasswd[] =
2ff057
{
2ff057
	"name", "uid", "gid", "dir", "shell", "gecos", "passwd", NULL
2ff057
};
2ff057
2ff057
2ff057
static int Pgetpasswd(lua_State *L)		/** getpasswd(name or id) */
2ff057
{
2ff057
	struct passwd *p=NULL;
2ff057
	if (lua_isnoneornil(L, 1))
2ff057
		p = getpwuid(geteuid());
2ff057
	else if (lua_isnumber(L, 1))
2ff057
		p = getpwuid((uid_t)lua_tonumber(L, 1));
2ff057
	else if (lua_isstring(L, 1))
2ff057
		p = getpwnam(lua_tostring(L, 1));
2ff057
	else
2ff057
		typerror(L, 1, "string or number");
2ff057
	if (p==NULL)
2ff057
		lua_pushnil(L);
2ff057
	else
2ff057
		doselection(L, 2, Sgetpasswd, Fgetpasswd, p);
2ff057
	return 1;
2ff057
}
2ff057
2ff057
2ff057
static int Pgetgroup(lua_State *L)		/** getgroup(name or id) */
2ff057
{
2ff057
	struct group *g=NULL;
2ff057
	if (lua_isnumber(L, 1))
2ff057
		g = getgrgid((gid_t)lua_tonumber(L, 1));
2ff057
	else if (lua_isstring(L, 1))
2ff057
		g = getgrnam(lua_tostring(L, 1));
2ff057
	else
2ff057
		typerror(L, 1, "string or number");
2ff057
	if (g==NULL)
2ff057
		lua_pushnil(L);
2ff057
	else
2ff057
	{
2ff057
		int i;
2ff057
		lua_newtable(L);
2ff057
		storestring(L, "name", g->gr_name);
2ff057
		storenumber(L, "gid", g->gr_gid);
2ff057
		for (i=0; g->gr_mem[i] != NULL; i++)
2ff057
			storeindex(L, i+1, g->gr_mem[i]);
2ff057
	}
2ff057
	return 1;
2ff057
}
2ff057
2ff057
2ff057
static int Psetuid(lua_State *L)		/** setuid(name or id) */
2ff057
{
2ff057
	return pushresult(L, setuid(mygetuid(L, 1)), NULL);
2ff057
}
2ff057
2ff057
2ff057
static int Psetgid(lua_State *L)		/** setgid(name or id) */
2ff057
{
2ff057
	return pushresult(L, setgid(mygetgid(L, 1)), NULL);
2ff057
}
2ff057
2ff057
struct mytimes
2ff057
{
2ff057
 struct tms t;
2ff057
 clock_t elapsed;
2ff057
};
2ff057
2ff057
#define pushtime(L,x)		lua_pushnumber(L,((lua_Number)x)/CLOCKS_PER_SEC)
2ff057
2ff057
static int Ftimes(lua_State *L, int i, const void *data)
2ff057
{
2ff057
	const struct mytimes *t=data;
2ff057
	switch (i)
2ff057
	{
2ff057
		case 0: pushtime(L, t->t.tms_utime); break;
2ff057
		case 1: pushtime(L, t->t.tms_stime); break;
2ff057
		case 2: pushtime(L, t->t.tms_cutime); break;
2ff057
		case 3: pushtime(L, t->t.tms_cstime); break;
2ff057
		case 4: pushtime(L, t->elapsed); break;
2ff057
	}
2ff057
	return 1;
2ff057
}
2ff057
2ff057
static const char *const Stimes[] =
2ff057
{
2ff057
	"utime", "stime", "cutime", "cstime", "elapsed", NULL
2ff057
};
2ff057
2ff057
#define storetime(L,name,x)	storenumber(L,name,(lua_Number)x/CLOCKS_PER_SEC)
2ff057
2ff057
static int Ptimes(lua_State *L)			/** times() */
2ff057
{
2ff057
	struct mytimes t;
2ff057
	t.elapsed = times(&t.t);
2ff057
	return doselection(L, 1, Stimes, Ftimes, &t);
2ff057
}
2ff057
2ff057
2ff057
struct mystat
2ff057
{
2ff057
	struct stat s;
2ff057
	char mode[10];
2ff057
	const char *type;
2ff057
};
2ff057
2ff057
static int Fstat(lua_State *L, int i, const void *data)
2ff057
{
2ff057
	const struct mystat *s=data;
2ff057
	switch (i)
2ff057
	{
2ff057
		case 0: lua_pushstring(L, s->mode); break;
2ff057
		case 1: lua_pushnumber(L, s->s.st_ino); break;
2ff057
		case 2: lua_pushnumber(L, s->s.st_dev); break;
2ff057
		case 3: lua_pushnumber(L, s->s.st_nlink); break;
2ff057
		case 4: lua_pushnumber(L, s->s.st_uid); break;
2ff057
		case 5: lua_pushnumber(L, s->s.st_gid); break;
2ff057
		case 6: lua_pushnumber(L, s->s.st_size); break;
2ff057
		case 7: lua_pushnumber(L, s->s.st_atime); break;
2ff057
		case 8: lua_pushnumber(L, s->s.st_mtime); break;
2ff057
		case 9: lua_pushnumber(L, s->s.st_ctime); break;
2ff057
		case 10:lua_pushstring(L, s->type); break;
2ff057
		case 11:lua_pushnumber(L, s->s.st_mode); break;
2ff057
	}
2ff057
	return 1;
2ff057
}
2ff057
2ff057
static const char *const Sstat[] =
2ff057
{
2ff057
	"mode", "ino", "dev", "nlink", "uid", "gid",
2ff057
	"size", "atime", "mtime", "ctime", "type", "_mode",
2ff057
	NULL
2ff057
};
2ff057
2ff057
static int Pstat(lua_State *L)			/** stat(path,[selector]) */
2ff057
{
2ff057
	struct mystat s;
2ff057
	const char *path=luaL_checkstring(L, 1);
2ff057
	if (lstat(path,&s.s)==-1) return pusherror(L, path);
2ff057
	s.type=filetype(s.s.st_mode);
2ff057
	modechopper(s.s.st_mode, s.mode);
2ff057
	return doselection(L, 2, Sstat, Fstat, &s);
2ff057
}
2ff057
2ff057
2ff057
static int Puname(lua_State *L)			/** uname([string]) */
2ff057
{
2ff057
	struct utsname u;
2ff057
	luaL_Buffer b;
2ff057
	const char *s;
2ff057
	if (uname(&u) == -1) return pusherror(L, NULL);
2ff057
	luaL_buffinit(L, &b);
2ff057
	for (s=luaL_optstring(L, 1, "%s %n %r %v %m"); *s; s++)
2ff057
		if (*s!='%')
2ff057
			luaL_addchar(&b, *s);
2ff057
		else switch (*++s)
2ff057
		{
2ff057
			case '%': luaL_addchar(&b, *s); break;
2ff057
			case 'm': luaL_addstring(&b,u.machine); break;
2ff057
			case 'n': luaL_addstring(&b,u.nodename); break;
2ff057
			case 'r': luaL_addstring(&b,u.release); break;
2ff057
			case 's': luaL_addstring(&b,u.sysname); break;
2ff057
			case 'v': luaL_addstring(&b,u.version); break;
2ff057
			default: badoption(L, 2, "format", *s); break;
2ff057
		}
2ff057
	luaL_pushresult(&b);
2ff057
	return 1;
2ff057
}
2ff057
2ff057
2ff057
static const int Kpathconf[] =
2ff057
{
2ff057
	_PC_LINK_MAX, _PC_MAX_CANON, _PC_MAX_INPUT, _PC_NAME_MAX, _PC_PATH_MAX,
2ff057
	_PC_PIPE_BUF, _PC_CHOWN_RESTRICTED, _PC_NO_TRUNC, _PC_VDISABLE,
2ff057
	-1
2ff057
};
2ff057
2ff057
static int Fpathconf(lua_State *L, int i, const void *data)
2ff057
{
2ff057
	const char *path=data;
2ff057
	lua_pushnumber(L, pathconf(path, Kpathconf[i]));
2ff057
	return 1;
2ff057
}
2ff057
2ff057
static const char *const Spathconf[] =
2ff057
{
2ff057
	"link_max", "max_canon", "max_input", "name_max", "path_max",
2ff057
	"pipe_buf", "chown_restricted", "no_trunc", "vdisable",
2ff057
	NULL
2ff057
};
2ff057
2ff057
static int Ppathconf(lua_State *L)		/** pathconf(path,[selector]) */
2ff057
{
2ff057
	const char *path=luaL_checkstring(L, 1);
2ff057
	return doselection(L, 2, Spathconf, Fpathconf, path);
2ff057
}
2ff057
2ff057
2ff057
static const int Ksysconf[] =
2ff057
{
2ff057
	_SC_ARG_MAX, _SC_CHILD_MAX, _SC_CLK_TCK, _SC_NGROUPS_MAX, _SC_STREAM_MAX,
2ff057
	_SC_TZNAME_MAX, _SC_OPEN_MAX, _SC_JOB_CONTROL, _SC_SAVED_IDS, _SC_VERSION,
2ff057
	-1
2ff057
};
2ff057
2ff057
static int Fsysconf(lua_State *L, int i, const void *data)
2ff057
{
2ff057
	lua_pushnumber(L, sysconf(Ksysconf[i]));
2ff057
	return 1;
2ff057
}
2ff057
2ff057
static const char *const Ssysconf[] =
2ff057
{
2ff057
	"arg_max", "child_max", "clk_tck", "ngroups_max", "stream_max",
2ff057
	"tzname_max", "open_max", "job_control", "saved_ids", "version",
2ff057
	NULL
2ff057
};
2ff057
2ff057
static int Psysconf(lua_State *L)		/** sysconf([selector]) */
2ff057
{
2ff057
	return doselection(L, 1, Ssysconf, Fsysconf, NULL);
2ff057
}
2ff057
2ff057
static int Pmkstemp(lua_State *L)
2ff057
{
2ff057
	const char *path;
2ff057
	char *dynpath;
2ff057
	int fd;
2ff057
	FILE **f;
2ff057
2ff057
	path = luaL_checkstring(L, 1);
2ff057
	if (path == NULL)
2ff057
		return 0;
2ff057
	dynpath = rstrdup(path);
2ff057
	fd = mkstemp(dynpath);
2ff057
	f = (FILE**)lua_newuserdata(L, sizeof(FILE*));
2ff057
	if (f == NULL) {
2ff057
		close(fd);
2ff057
		free(dynpath);
2ff057
		return 0;
2ff057
	}
2ff057
	*f = fdopen(fd, "a+");
2ff057
	lua_pushstring(L, dynpath);
2ff057
	free(dynpath);
2ff057
	luaL_getmetatable(L, "FILE*");
2ff057
	if (lua_isnil(L, -1)) {
2ff057
		lua_pop(L, 1);
2ff057
		return luaL_error(L, "FILE* metatable not available "
2ff057
			      "(io not loaded?)");
2ff057
	} else {
2ff057
		lua_setmetatable(L, -3);
2ff057
	}
2ff057
	return 2;
2ff057
}
2ff057
2ff057
static int Predirect2null(lua_State *L)
2ff057
{
2ff057
    int target_fd, fd, r, e;
2ff057
2ff057
    if (!have_forked)
2ff057
	return luaL_error(L, "silence_file_descriptor not permitted in this context");
2ff057
2ff057
    target_fd = luaL_checkinteger(L, 1);
2ff057
2ff057
    r = fd = open("/dev/null", O_WRONLY);
2ff057
    if (fd >= 0 && fd != target_fd) {
2ff057
	r = dup2(fd, target_fd);
2ff057
	e = errno;
2ff057
	(void) close(fd);
2ff057
	errno = e;
2ff057
    }
2ff057
    return pushresult(L, r, NULL);
2ff057
}
2ff057
2ff057
static const luaL_Reg R[] =
2ff057
{
2ff057
	{"access",		Paccess},
2ff057
	{"chdir",		Pchdir},
2ff057
	{"chmod",		Pchmod},
2ff057
	{"chown",		Pchown},
2ff057
	{"ctermid",		Pctermid},
2ff057
	{"dir",			Pdir},
2ff057
	{"errno",		Perrno},
2ff057
	{"exec",		Pexec},
2ff057
	{"files",		Pfiles},
2ff057
	{"fork",		Pfork},
2ff057
	{"getcwd",		Pgetcwd},
2ff057
	{"getenv",		Pgetenv},
2ff057
	{"getgroup",		Pgetgroup},
2ff057
	{"getlogin",		Pgetlogin},
2ff057
	{"getpasswd",		Pgetpasswd},
2ff057
	{"getprocessid",	Pgetprocessid},
2ff057
	{"kill",		Pkill},
2ff057
	{"link",		Plink},
2ff057
	{"mkdir",		Pmkdir},
2ff057
	{"mkfifo",		Pmkfifo},
2ff057
	{"mkstemp",		Pmkstemp},
2ff057
	{"pathconf",		Ppathconf},
2ff057
	{"putenv",		Pputenv},
2ff057
	{"readlink",		Preadlink},
2ff057
	{"rmdir",		Prmdir},
2ff057
	{"setgid",		Psetgid},
2ff057
	{"setuid",		Psetuid},
2ff057
	{"sleep",		Psleep},
2ff057
	{"stat",		Pstat},
2ff057
	{"symlink",		Psymlink},
2ff057
	{"sysconf",		Psysconf},
2ff057
	{"times",		Ptimes},
2ff057
	{"ttyname",		Pttyname},
2ff057
	{"umask",		Pumask},
2ff057
	{"uname",		Puname},
2ff057
	{"unlink",		Punlink},
2ff057
	{"utime",		Putime},
2ff057
	{"wait",		Pwait},
2ff057
	{"setenv",		Psetenv},
2ff057
	{"unsetenv",		Punsetenv},
2ff057
	{"redirect2null",       Predirect2null},
2ff057
	{NULL,			NULL}
2ff057
};
2ff057
2ff057
LUALIB_API int luaopen_posix (lua_State *L)
2ff057
{
2ff057
	luaL_openlib(L, MYNAME, R, 0);
2ff057
	lua_pushliteral(L,"version");		/** version */
2ff057
	lua_pushliteral(L,MYVERSION);
2ff057
	lua_settable(L,-3);
2ff057
	return 1;
2ff057
}
2ff057
2ff057
/* RPM specific overrides for Lua standard library */
2ff057
2ff057
static int exit_override(lua_State *L)
2ff057
{
2ff057
    if (!have_forked)
2ff057
	return luaL_error(L, "exit not permitted in this context");
2ff057
2ff057
    exit(luaL_optinteger(L, 1, EXIT_SUCCESS));
2ff057
}
2ff057
2ff057
static const luaL_Reg os_overrides[] =
2ff057
{
2ff057
    {"exit",    exit_override},
2ff057
    {NULL,      NULL}
2ff057
};
2ff057
2ff057
#ifndef lua_pushglobaltable
2ff057
#define lua_pushglobaltable(L) lua_pushvalue(L, LUA_GLOBALSINDEX)
2ff057
#endif
2ff057
2ff057
int luaopen_rpm_os(lua_State *L)
2ff057
{
2ff057
    lua_pushglobaltable(L);
2ff057
    luaL_openlib(L, "os", os_overrides, 0);
2ff057
    return 0;
2ff057
}
2ff057