663 lines · 14.7 KB · C
RawDownload
#include <unistd.h>#include <ctype.h>#include <errno.h>#include <stddef.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include "lua.h" #include "lauxlib.h"#include "lualib.h"#include "lp9lib.h" /* macro to `unsign' a character */#define uchar(c)        ((unsigned char)(c)) static int pushresult (lua_State *L, int i, const char *msg);static int notefun(void *a, char *msg) ;int killflag = 0; static int pusherr(lua_State *L){    char buf[80];    rerrstr(buf,sizeof(buf));    return pushresult(L,0,buf);} static int getintfield (lua_State *L, const char *key,int res) {  lua_getfield(L, -1, key);  if (lua_isnumber(L, -1))    res = (int)lua_tointeger(L, -1);  lua_pop(L, 1);  return res;} static char *getstrfield (lua_State *L, const char *key) {  char *res = nil;  lua_getfield(L, -1, key);  if (lua_isstring(L, -1))    res = lua_tostring(L, -1);  lua_pop(L, 1);  return res;} static void setintfield (lua_State *L, const char *key, long value) {  lua_pushinteger(L, value);  lua_setfield(L, -2, key);} static void setstrfield (lua_State *L, const char *key, char *value) {  lua_pushstring(L, value);  lua_setfield(L, -2, key);} static int p9_access(lua_State *L) {  const char *name = luaL_checkstring(L, 1);  const ulong mode = luaL_checkinteger(L, 2);  int r = access(name,mode); // r is 0 or -1, 0: true, -1:false  lua_pushboolean(L, !r); // 1: true, 0:false  return 1;} /*	look /sys/src/ape/lib/ap/plan9	*/static int p9_open(lua_State *L){  const int na = lua_gettop(L);    /* number of arguments */  const char *name = luaL_checkstring(L, 1);  const char *mode = "r";  int omode = OREAD;  if (lua_isnoneornil(L, 2))  /* called without args? */    na = 1;  if(na > 1)    mode = luaL_checkstring(L, 2);  int fd = -2;  if(strcmp(mode,"r") == 0)    fd = open(name,O_RDONLY);  else if(strcmp(mode,"w") == 0)    fd = open(name,O_WRONLY);  else if(strcmp(mode,"rw") == 0)    fd = open(name,O_RDWR);  else if(strcmp(mode,"w+") == 0)    fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0666L);  else if(strcmp(mode,"a") == 0){    fd = open(name,O_WRONLY|O_APPEND);    //seek(fd,0,2);  }  if(fd == -2){    lua_pushstring(L,"invalid mode");    lua_error(L);  }  if(fd < 0)    return pusherr(L);  lua_pushinteger(L, fd);  return 1;} static int p9_close(lua_State *L){  const int fd = luaL_checkinteger(L, 1);  close(fd);  lua_pushnil(L);  return 1;} /*	stolen from liolib.c	*/static int pushresult (lua_State *L, int i, const char *msg) {  int en = errno;  /* calls to Lua API may change this value */  if (i) {    lua_pushboolean(L, 1);    return 1;  }  else {    lua_pushnil(L);    if (msg)      lua_pushfstring(L, "%s: %s", msg, strerror(en));    else      lua_pushfstring(L, "%s", strerror(en));    lua_pushinteger(L, en);    return 3;  }}  static int p9_read(lua_State *L){  const int na = lua_gettop(L);    /* number of arguments */  const int fd = luaL_checkinteger(L, 1);  char *type = "string";  long n;  char *status = nil;  char buf[16384];  if(na == 1){	luaL_Buffer lb; 	luaL_buffinit(L, &lb);    while((n = _READ(fd,buf,sizeof(buf))) > 0)      luaL_addlstring(&lb,buf,n);    if(n < 0)      return pusherr(L);    luaL_pushresult(&lb);  }  else{    ulong m;    char *p = buf;    m = luaL_checkinteger(L, 2);    if(m > sizeof(buf))      p = malloc(m);    if(p == nil){      lua_pushstring(L,"malloc");      lua_error(L);    }    n = _READ(fd,p,m);    if(n < 0){      if(p != buf)        free(p);      return pusherr(L);    }    if(n == 0)      lua_pushnil(L);    else      lua_pushlstring(L,p,n);    if(p != buf)      free(p);  }  return 1;} static int p9_write(lua_State *L){  const int fd = luaL_checkinteger(L, 1);  size_t size;  const char *data = luaL_checklstring(L, 2, &size);  long n;  n = _WRITE(fd,data,size);  if(n < 0)    return pusherr(L);    /* you might think this case should raise error     * however we have cases that we must neglect the return value     * see announce.c	*/  lua_pushinteger(L, n);  return 1;} static int p9_seek(lua_State *L){  const int na = lua_gettop(L);    /* number of arguments */  const int fd = luaL_checkinteger(L, 1);  vlong off = 0;  int how = 0;  char *_how = nil;  if(na > 1)    off = luaL_checkinteger(L, 2);  if(na > 2){    _how = luaL_checkstring(L, 3);    if(strcmp(_how,"set") == 0)      how = 0;    else if(strcmp(_how,"cur") == 0)      how = 1;    else if(strcmp(_how,"end") == 0)      how = 2;    else{      lua_pushstring(L,"must be one of \"set\",\"cur\",\"end\"");      lua_error(L);    }  }  off = seek(fd,off,how);  if(off < 0){    lua_pushstring(L,"seek");    lua_error(L);  }  else    lua_pushinteger(L, (int)off);  return 1;}  static int p9_bind(lua_State *L){  const int na = lua_gettop(L);    /* number of arguments */  const char *name = luaL_checkstring(L, 1);  const char *old = luaL_checkstring(L, 2);  char *mode = "";  ulong flag = 0;  if(na > 2)    mode = luaL_checkstring(L, 3);  if(strchr(mode,'a'))    flag |= MAFTER;  if(strchr(mode,'b'))    flag |= MBEFORE;  if(strchr(mode,'c'))    flag |= MCREATE;   if((flag&MAFTER)&&(flag&MBEFORE)){    lua_pushstring(L,"flags:");    lua_error(L);  }  if(bind(name,old,flag) < 0)    lua_pushboolean(L,0);  else    lua_pushboolean(L,1);  return 1;} static int p9_unmount(lua_State *L){  const int na = lua_gettop(L);    /* number of arguments */  const char *name = luaL_checkstring(L, 1);  const char *old = nil;  if(na > 1)    old = luaL_checkstring(L, 2);  if(old == nil){    old = name;    name = nil;  }  if(unmount(name,old) < 0)    lua_pushboolean(L,0);  else    lua_pushboolean(L,1);  return 1;} static int pushdir(lua_State *L, Dir *dir){    lua_createtable(L, 0, 12);  /* 12 = number of fields */    char buf[64];    setintfield(L, "type", dir->type);    setintfield(L, "dev", dir->dev);    snprint(buf,sizeof(buf),      "%ullx-%uld-%d",dir->qid.path,dir->qid.vers,dir->qid.type);    setstrfield(L, "qid", buf);    /* lua is buggy in handling integer such as 0x80000000	 * thereby we use string "mode" */    snprint(buf,sizeof(buf),"0%uo",dir->mode);    setstrfield(L, "mode", buf);    setintfield(L, "atime", dir->atime);    setintfield(L, "mtime", dir->mtime);    setintfield(L, "length", dir->length);    setstrfield(L, "name", dir->name);    setstrfield(L, "uid", dir->uid);    setstrfield(L, "gid", dir->gid);    setstrfield(L, "muid", dir->muid);    return 0;} static int p9_dirstat(lua_State *L){  const char *name = luaL_checkstring(L, 1);  Dir *dir;  /* look os.date() for helpful reference */  dir = _dirstat(name);  if(dir == nil) /* non-existent */    lua_pushnil(L);  else{    pushdir(L,dir);    free(dir);  }  return 1;} /* 	dirwstat(file,mode) where mode is a table such as {uid="alice"} * 	we have a good example: os.time() */static int p9_dirwstat(lua_State *L){  const char *name = luaL_checkstring(L, 1);  const mask = 0x80000000;  ulong mode = 0;  ulong mtime;  char *uid,*gid,*smode;  Dir *dir;   if (lua_isnoneornil(L, 1))  /* called without args? */    return luaL_error(L, LUA_QL("setmode") " need a table");  luaL_checktype(L, 2, LUA_TTABLE);  lua_settop(L, 2);  /* make sure table is at the top */  /* mode in dirstat is string octal, so we must ... */  smode = getstrfield(L,"mode");  if(smode)    mode = strtol(smode,nil,8);    mtime = getintfield(L,"mtime",0);  uid = getstrfield(L,"uid");  gid = getstrfield(L,"gid");   /* debug */  //fprintf(stderr,"mode=0%o mtime=%lu uid=%s gui=%s\n",mode,mtime,uid,gid);   /* we should keep dir bit of mode for safty */  dir = _dirstat(name);  if(dir == nil) /* non-existent */    lua_pushnil(L);  else{    if(mode)      dir->mode = ((dir->mode)&mask)?(mode|mask):(mode&(~mask));    //fprintf(stderr,"mode=0%o\n",dir->mode);     if(mtime) dir->mtime = mtime;    if(uid) dir->uid = uid;    if(gid) dir->gid = gid;    _dirwstat(name, dir);  }  free(dir);  return 1;} static int p9_mkdir(lua_State *L){  /* return nil in success */  ulong mode =  0777L;  int fd;  char buf[128];  const int na = lua_gettop(L);    /* number of arguments */  const char *name = luaL_checkstring(L, 1);  const char *m;  if(na > 1){    m = luaL_checkstring(L, 2);    mode = strtoul(m, &m, 8);    if(mode > 0777){      snprint(buf,sizeof(buf),"mkdir: inappropriate mode.");      lua_pushstring(L,buf);	  lua_error(L);      return 1;    }  }  fd = create(name,OREAD, DMDIR | mode);  if(fd < 0){    snprint(buf,sizeof(buf),"create: %r");    lua_pushstring(L,buf);	lua_error(L);  }else{    lua_pushboolean(L, 1);	close(fd);  }  return 1;} static int compar(Dir *a, Dir *b){	return strcmp(a->name, b->name);} static int p9_readdir(lua_State *L){  const int m = lua_gettop(L);    /* number of arguments */  const char *name = luaL_checkstring(L, 1);  const int t = 0;  Dir *dir;  long n;  int fd;  int i,r;   if(m > 1) t = lua_toboolean(L,2);  fd = open(name,O_RDONLY);  if(fd < 0){/* non-existent */    lua_pushnil(L);    return 1;  }   if((n = _dirreadall(fd, &dir)) < 0){    lua_pushnil(L);    close(fd);    return 1;  }  /* sort by name */  qsort(dir, n, sizeof(Dir), (int (*)(void*, void*))compar);   lua_createtable(L, 0, 1);  /* n = size of array */   if(t){    for(i = 0; i < n; i++){      pushdir(L, &dir[i]);      lua_setfield(L,-2,dir[i].name);    }  }  else{    for(i = 0; i < n; i++){      r = ((dir[i].mode&DMDIR) != (ulong)0);      lua_pushboolean(L, r);      lua_setfield(L,-2,dir[i].name);    }  }  close(fd);  return 1;// number of pop}  /*	usage: bit(n,"&", m)	 */static int p9_bit(lua_State *L) {	ulong n = luaL_checkinteger(L, 1);	const char *s = luaL_checkstring(L, 2);	const ulong m = luaL_checkinteger(L, 3);	if(strcmp(s,"&") == 0) n &= m;	else if(strcmp(s,"|") == 0) n |= m;	else if(strcmp(s,"^") == 0) n = n ^ m;	else if(strcmp(s,"<<") == 0) n = n << m;	else if(strcmp(s,">>") == 0) n = n >> m;	else {		lua_pushstring(L,"invalid operator");		lua_error(L);	}	lua_pushinteger(L, n);	return 1;} /*	usage: popen(prog) 	prog is rc command list	*/static int p9_popen(lua_State *L) {	char *prog = luaL_checkstring(L, 1);	int fd[2];	if(pipe(fd)<0){		lua_pushstring(L,"pipe");		lua_error(L);	}	switch(rfork(RFFDG|RFPROC|RFNOTEG|RFREND|RFNAMEG)){	/*	RFNAMEG: the new process inherits a copy of the parent's name space.	*	RFNAMEG is required so that nomnt() does not make effect to parent	*	namespace	*/	case -1:		lua_pushstring(L,"rfork");		lua_error(L);	case 0: // child: read stdin, and write to stdout		close(fd[0]);		dup2(fd[1], 0); // the stdin is redirected to fd		dup2(fd[1], 1); // the stdout is redirected to fd		//dup2(fd[1], 2); // the stderr is also redirected to fd		close(fd[1]);		execl("/bin/rc", "rc", "-c", prog, nil);		/* not reached in normal case*/		lua_pushstring(L,"exec");		lua_error(L);	default:// parent: read data from the child		close(fd[1]);		break;	}	lua_pushinteger(L, fd[0]);	return 1;}  static int p9_fork(lua_State *L) {	int pid;	pid = fork();	if(pid < 0){		lua_pushstring(L,"fork");		lua_error(L);	}	lua_pushinteger(L, pid);	return 1;} static int p9_wait(lua_State *L){	Waitmsg *msg;	int na = lua_gettop(L);    /* number of arguments */	int pid = 0;	if(na > 0)		pid = luaL_checkinteger(L, 1);	//msg = wait(); // ape wait	msg = _WAIT(); // plan9 wait    if(msg == nil)		goto noproc;	if(pid != 0){		while(msg->pid != pid){			free(msg);			//msg = wait();			msg = _WAIT();		    if(msg == nil)				goto noproc;		}	}	lua_pushinteger(L, msg->pid);	if(msg->msg[0] == 0)		lua_pushnil(L);	else		lua_pushstring(L,msg->msg);	lua_pushinteger(L, msg->time[0]);	lua_pushinteger(L, msg->time[1]);

Lines 1–500 of 663.