shithub: drawcpu

ref: 271a7db1cd9afb4cf841101188199c3a0d0f4c62
dir: /rc/drawcpu.c/

View raw version
/*
 * Plan 9 versions of system-specific functions
 *	By convention, exported routines herein have names beginning with an
 *	upper case letter.
 */

#include "rc.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
#include "getflags.h"

#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/wait.h>

static void execfinit(void);

builtin Builtin[] = {
	"cd",		execcd,
	"whatis",	execwhatis,
	"eval",		execeval,
	"exec",		execexec,	/* but with popword first */
	"exit",		execexit,
	"shift",	execshift,
	"wait",		execwait,
	".",		execdot,
	"flag",		execflag,
	"finit",	execfinit,
	0
};

// TODO: PREFIX "/lib/rcmain"
char Rcmain[]="./rc/rcmain.unix";
char Fdprefix[]="/dev/fd/";

char *Signame[NSIG];

/*
 * finit could be removed but is kept for
 * backwards compatibility, see: rcmain.plan9
 */
static void
execfinit(void)
{
	char *cmds = estrdup("for(i in '/env/fn#'*){. -bq $i}\n");
	int line = runq->line;
	poplist();
	execcmds(openiocore(cmds, strlen(cmds)), estrdup(srcfile(runq)), runq->local, runq->redir);
	runq->lex->line = line;
	runq->lex->qflag = 1;
}

char*
Env(char *name, int fn)
{
	static char buf[128];

	strcpy(buf, "/env/");
	if(fn) strcat(buf, "fn#");
	return strncat(buf, name, sizeof(buf)-1);
}

void
Vinit(void)
{
	int fd;
	DIR *dir;
	struct dirent *ent;

	dir = opendir("/env");
	if(dir == nil){
		pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
		return;
	}
	for(;;){
		ent = readdir(dir);
		if (ent == nil)
			break;
		if(ent->d_namlen<=0 || strncmp(ent->d_name, "fn#", 3)==0)
			continue;
		if((fd = Open(Env(ent->d_name, 0), 0))>=0){
			io *f = openiofd(fd);
			word *w = 0, **wp = &w;
			char *s;
			while((s = rstr(f, "")) != 0){
				*wp = Newword(s, (word*)0);
				wp = &(*wp)->next;
			}
			closeio(f);
			setvar(ent->d_name, w);
			vlook(ent->d_name)->changed = 0;
		}
		free(ent);
	}
	closedir(dir);
}

char*
Errstr(void)
{
	return strerror(errno);
}

/* Can we do this inside the kernel? */
int
Waitfor(int pid)
{
	thread *p;
	char num[12];
	int wpid, status;

	if(pid >= 0 && !havewaitpid(pid))
		return 0;
	while((wpid = wait(&status))!=-1){
		delwaitpid(wpid);
		inttoascii(num, WIFSIGNALED(status)?WTERMSIG(status)+1000:WEXITSTATUS(status));
		if(wpid==pid){
			setstatus(num);
			return 0;
		}
		for(p = runq->ret;p;p = p->ret)
			if(p->pid==wpid){
				p->pid=-1;
				p->status = estrdup(num);
				break;
			}
	}
	if(errno==EINTR) return -1;
	return 0;
}

static void
addenv(var *v)
{
	word *w;
	int fd;
	io *f;

	if(v->changed){
		v->changed = 0;
		if((fd = Creat(Env(v->name, 0)))<0)
			pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
		else{
			f = openiofd(fd);
			for(w = v->val;w;w = w->next){
				pstr(f, w->word);
				pchr(f, '\0');
			}
			flushio(f);
			closeio(f);
		}
	}
	if(v->fnchanged){
		v->fnchanged = 0;
		if((fd = Creat(Env(v->name, 1)))<0)
			pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
		else{
			f = openiofd(fd);
			if(v->fn)
				pfmt(f, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
			flushio(f);
			closeio(f);
		}
	}
}

static void
updenvlocal(var *v)
{
	if(v){
		updenvlocal(v->next);
		addenv(v);
	}
}

void
Updenv(void)
{
	var *v, **h;
	for(h = gvar;h!=&gvar[NVAR];h++)
		for(v=*h;v;v = v->next)
			addenv(v);
	if(runq)
		updenvlocal(runq->local);
	if(err)
		flushio(err);
}

void
Exec(char **argv)
{
	// TODO: execve after loading env to string
	execv(argv[0], argv+1);
}

int
Fork(void)
{
	Updenv();
	return fork();
}

void*
Opendir(char *name)
{
	return opendir(name);
}

char*
Readdir(void *arg, int onlydirs)
{
	DIR *rd = arg;
	struct dirent *ent = readdir(rd);
	if(ent == NULL)
		return 0;
	return ent->d_name;
}

void
Closedir(void *arg)
{
	DIR *rd = arg;
	closedir(rd);
}

static void
sighandler(int sig)
{
	trap[sig]++;
	ntrap++;
}

// TODO: Use kernel sighandling 
void
Trapinit(void)
{
	int i;

	Signame[0] = "sigexit";

#ifdef SIGINT
	Signame[SIGINT] = "sigint";
#endif
#ifdef SIGTERM
	Signame[SIGTERM] = "sigterm";
#endif
#ifdef SIGHUP
	Signame[SIGHUP] = "sighup";
#endif
#ifdef SIGQUIT
	Signame[SIGQUIT] = "sigquit";
#endif
#ifdef SIGPIPE
	Signame[SIGPIPE] = "sigpipe";
#endif
#ifdef SIGUSR1
	Signame[SIGUSR1] = "sigusr1";
#endif
#ifdef SIGUSR2
	Signame[SIGUSR2] = "sigusr2";
#endif
#ifdef SIGBUS
	Signame[SIGBUS] = "sigbus";
#endif
#ifdef SIGWINCH
	Signame[SIGWINCH] = "sigwinch";
#endif

	for(i=1; i<NSIG; i++) if(Signame[i]){
#ifdef SA_RESTART
		struct sigaction a;

		sigaction(i, NULL, &a);
		a.sa_flags &= ~SA_RESTART;
		a.sa_handler = sighandler;
		sigaction(i, &a, NULL);
#else
		signal(i, sighandler);
#endif
	}
}

long
Write(int fd, void *buf, long cnt)
{
	return write(fd, buf, cnt);
}

long
Read(int fd, void *buf, long cnt)
{
	return read(fd, buf, cnt);
}

long
Seek(int fd, long cnt, long whence)
{
	return seek(fd, cnt, whence);
}

int
Executable(char *file)
{
	Dir *statbuf;
	int ret;

	statbuf = dirstat(file);
	if(statbuf == nil)
		return 0;
	ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
	free(statbuf);
	return ret;
}

int
Open(char *file, int mode)
{
	static int tab[] = {OREAD,OWRITE,ORDWR,OREAD|ORCLOSE};
	return open(file, tab[mode&3]);
}

void
Close(int fd)
{
	close(fd);
}

int
Creat(char *file)
{
	return create(file, OWRITE, 0666L);
}

int
Dup(int a, int b)
{
	return dup(a, b);
}

int
Dup1(int a)
{
	return dup(a, -1);
}

void
Exit(void)
{
	Updenv();
	exits(truestatus()?"":getstatus());
}

void
Noerror(void)
{
	errno = 0;
}

int
Isatty(int fd)
{
	return isatty(fd);
}

void
Abort(void)
{
	abort();
}

int
Chdir(char *dir)
{
	return chdir(dir);
}

void
Prompt(char *s)
{
	pstr(err, s);
	flushio(err);
}