blob: da9d8679e6794bb6c9040291681aa800139090ac [file] [log] [blame]
/*
* 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"
char *Signame[]={
"sigexit", "sighup", "sigint", "sigquit",
"sigalrm", "sigkill", "sigfpe", "sigterm",
0
};
char *syssigname[]={
"exit", /* can't happen */
"hangup",
"interrupt",
"quit", /* can't happen */
"alarm",
"kill",
"sys: fp: ",
"term",
0
};
char*
Rcmain(void)
{
return unsharp("#9/rcmain");
}
char Fdprefix[]="/dev/fd/";
long readnb(int, char *, long);
void execfinit(void);
void execbind(void);
void execmount(void);
void execulimit(void);
void execumask(void);
void execrfork(void);
builtin Builtin[]={
"cd", execcd,
"whatis", execwhatis,
"eval", execeval,
"exec", execexec, /* but with popword first */
"exit", execexit,
"shift", execshift,
"wait", execwait,
".", execdot,
"finit", execfinit,
"flag", execflag,
"ulimit", execulimit,
"umask", execumask,
"rfork", execrfork,
0
};
void
execrfork(void)
{
int arg;
char *s;
switch(count(runq->argv->words)){
case 1:
arg = RFENVG|RFNOTEG|RFNAMEG;
break;
case 2:
arg = 0;
for(s = runq->argv->words->next->word;*s;s++) switch(*s){
default:
goto Usage;
case 'n':
arg|=RFNAMEG; break;
case 'N':
arg|=RFCNAMEG;
break;
case 'e':
/* arg|=RFENVG; */ break;
case 'E':
arg|=RFCENVG; break;
case 's':
arg|=RFNOTEG; break;
case 'f':
arg|=RFFDG; break;
case 'F':
arg|=RFCFDG; break;
}
break;
default:
Usage:
pfmt(err, "Usage: %s [nNeEsfF]\n", runq->argv->words->word);
setstatus("rfork usage");
poplist();
return;
}
if(rfork(arg)==-1){
pfmt(err, "rc: %s failed\n", runq->argv->words->word);
setstatus("rfork failed");
}
else
setstatus("");
poplist();
}
#define SEP '\1'
char **environp;
struct word *enval(s)
register char *s;
{
register char *t, c;
register struct word *v;
for(t=s;*t && *t!=SEP;t++);
c=*t;
*t='\0';
v=newword(s, c=='\0'?(struct word *)0:enval(t+1));
*t=c;
return v;
}
void Vinit(void){
extern char **environ;
register char *s;
register char **env=environ;
environp=env;
for(;*env;env++){
for(s=*env;*s && *s!='(' && *s!='=';s++);
switch(*s){
case '\0':
/* pfmt(err, "rc: odd environment %q?\n", *env); */
break;
case '=':
*s='\0';
setvar(*env, enval(s+1));
*s='=';
break;
case '(': /* ignore functions for now */
break;
}
}
}
char **envp;
void Xrdfn(void){
char *p;
register char *s;
register int len;
for(;*envp;envp++){
s = *envp;
if(strncmp(s, "fn#", 3) == 0){
p = strchr(s, '=');
if(p == nil)
continue;
*p = ' ';
s[2] = ' ';
len = strlen(s);
execcmds(opencore(s, len));
s[len] = '\0';
return;
}
#if 0
for(s=*envp;*s && *s!='(' && *s!='=';s++);
switch(*s){
case '\0':
pfmt(err, "environment %q?\n", *envp);
break;
case '=': /* ignore variables */
break;
case '(': /* Bourne again */
s=*envp+3;
envp++;
len=strlen(s);
s[len]='\n';
execcmds(opencore(s, len+1));
s[len]='\0';
return;
}
#endif
}
Xreturn();
}
union code rdfns[4];
void execfinit(void){
static int first=1;
if(first){
rdfns[0].i=1;
rdfns[1].f=Xrdfn;
rdfns[2].f=Xjump;
rdfns[3].i=1;
first=0;
}
Xpopm();
envp=environp;
start(rdfns, 1, runq->local);
}
extern int mapfd(int);
int Waitfor(int pid, int unused0){
thread *p;
Waitmsg *w;
char errbuf[ERRMAX];
if(pid >= 0 && !havewaitpid(pid))
return 0;
while((w = wait()) != nil){
delwaitpid(w->pid);
if(w->pid==pid){
if(strncmp(w->msg, "signal: ", 8) == 0)
fprint(mapfd(2), "%d: %s\n", w->pid, w->msg);
setstatus(w->msg);
free(w);
return 0;
}
if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0)
fprint(2, "%d: %s\n", w->pid, w->msg);
for(p=runq->ret;p;p=p->ret)
if(p->pid==w->pid){
p->pid=-1;
strcpy(p->status, w->msg);
}
free(w);
}
rerrstr(errbuf, sizeof errbuf);
if(strcmp(errbuf, "interrupted")==0) return -1;
return 0;
}
char **mkargv(word *a)
{
char **argv=(char **)emalloc((count(a)+2)*sizeof(char *));
char **argp=argv+1; /* leave one at front for runcoms */
for(;a;a=a->next) *argp++=a->word;
*argp=0;
return argv;
}
/*
void addenv(var *v)
{
char envname[256];
word *w;
int f;
io *fd;
if(v->changed){
v->changed=0;
snprint(envname, sizeof envname, "/env/%s", v->name);
if((f=Creat(envname))<0)
pfmt(err, "rc: can't open %s: %r\n", envname);
else{
for(w=v->val;w;w=w->next)
write(f, w->word, strlen(w->word)+1L);
close(f);
}
}
if(v->fnchanged){
v->fnchanged=0;
snprint(envname, sizeof envname, "/env/fn#%s", v->name);
if((f=Creat(envname))<0)
pfmt(err, "rc: can't open %s: %r\n", envname);
else{
if(v->fn){
fd=openfd(f);
pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
closeio(fd);
}
close(f);
}
}
}
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);
}
*/
int
cmpenv(const void *a, const void *b)
{
return strcmp(*(char**)a, *(char**)b);
}
char **mkenv(){
register char **env, **ep, *p, *q;
register struct var **h, *v;
register struct word *a;
register int nvar=0, nchr=0, sep;
/*
* Slightly kludgy loops look at locals then globals
*/
for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
if((v==vlook(v->name)) && v->val){
nvar++;
nchr+=strlen(v->name)+1;
for(a=v->val;a;a=a->next)
nchr+=strlen(a->word)+1;
}
if(v->fn){
nvar++;
nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
}
}
env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr);
ep=env;
p=(char *)&env[nvar+1];
for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
if((v==vlook(v->name)) && v->val){
*ep++=p;
q=v->name;
while(*q) *p++=*q++;
sep='=';
for(a=v->val;a;a=a->next){
*p++=sep;
sep=SEP;
q=a->word;
while(*q) *p++=*q++;
}
*p++='\0';
}
if(v->fn){
*ep++=p;
#if 0
*p++='#'; *p++='('; *p++=')'; /* to fool Bourne */
*p++='f'; *p++='n'; *p++=' ';
q=v->name;
while(*q) *p++=*q++;
*p++=' ';
#endif
*p++='f'; *p++='n'; *p++='#';
q=v->name;
while(*q) *p++=*q++;
*p++='=';
q=v->fn[v->pc-1].s;
while(*q) *p++=*q++;
*p++='\n';
*p++='\0';
}
}
*ep=0;
qsort((char *)env, nvar, sizeof ep[0], cmpenv);
return env;
}
void Updenv(void){}
void Execute(word *args, word *path)
{
char **argv=mkargv(args);
char **env=mkenv();
char file[1024];
int nc;
Updenv();
for(;path;path=path->next){
nc=strlen(path->word);
if(nc<1024){
strcpy(file, path->word);
if(file[0]){
strcat(file, "/");
nc++;
}
if(nc+strlen(argv[1])<1024){
strcat(file, argv[1]);
execve(file, argv+1, env);
}
else werrstr("command name too long");
}
}
rerrstr(file, sizeof file);
pfmt(err, "%s: %s\n", argv[1], file);
efree((char *)argv);
}
#define NDIR 256 /* shoud be a better way */
int Globsize(char *p)
{
ulong isglob=0, globlen=NDIR+1;
for(;*p;p++){
if(*p==GLOB){
p++;
if(*p!=GLOB) isglob++;
globlen+=*p=='*'?NDIR:1;
}
else
globlen++;
}
return isglob?globlen:0;
}
#define NFD 50
#define NDBUF 32
struct{
Dir *dbuf;
int i;
int n;
}dir[NFD];
int Opendir(char *name)
{
Dir *db;
int f;
f=open(name, 0);
if(f==-1)
return f;
db = dirfstat(f);
if(db!=nil && (db->mode&DMDIR)){
if(f<NFD){
dir[f].i=0;
dir[f].n=0;
}
free(db);
return f;
}
free(db);
close(f);
return -1;
}
int Readdir(int f, char *p, int onlydirs)
{
int n;
USED(onlydirs); /* only advisory */
if(f<0 || f>=NFD)
return 0;
if(dir[f].i==dir[f].n){ /* read */
free(dir[f].dbuf);
dir[f].dbuf=0;
n=dirread(f, &dir[f].dbuf);
if(n>=0)
dir[f].n=n;
else
dir[f].n=0;
dir[f].i=0;
}
if(dir[f].i==dir[f].n)
return 0;
strcpy(p, dir[f].dbuf[dir[f].i].name);
dir[f].i++;
return 1;
}
void Closedir(int f){
if(f>=0 && f<NFD){
free(dir[f].dbuf);
dir[f].i=0;
dir[f].n=0;
dir[f].dbuf=0;
}
close(f);
}
int interrupted = 0;
void
notifyf(void *unused0, char *s)
{
int i;
for(i=0;syssigname[i];i++)
if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
if(strncmp(s, "sys: ", 5)!=0){
if(kidpid && !interrupted){
interrupted=1;
postnote(PNGROUP, kidpid, s);
}
interrupted = 1;
}
goto Out;
}
if(strcmp(s, "sys: window size change") != 0)
if(strcmp(s, "sys: write on closed pipe") != 0)
if(strcmp(s, "sys: child") != 0)
pfmt(err, "rc: note: %s\n", s);
noted(NDFLT);
return;
Out:
if(strcmp(s, "interrupt")!=0 || trap[i]==0){
trap[i]++;
ntrap++;
}
if(ntrap>=32){ /* rc is probably in a trap loop */
pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
abort();
}
noted(NCONT);
}
void Trapinit(void){
notify(notifyf);
}
void Unlink(char *name)
{
remove(name);
}
long Write(int fd, char *buf, long cnt)
{
return write(fd, buf, (long)cnt);
}
long Read(int fd, char *buf, long cnt)
{
int i;
i = readnb(fd, buf, cnt);
if(ntrap) dotrap();
return i;
}
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 Creat(char *file)
{
return create(file, 1, 0666L);
}
int Dup(int a, int b){
return dup(a, b);
}
int Dup1(int a){
return dup(a, -1);
}
void Exit(char *stat)
{
Updenv();
setstatus(stat);
exits(truestatus()?"":getstatus());
}
int Eintr(void){
return interrupted;
}
void Noerror(void){
interrupted=0;
}
int
Isatty(int fd){
return isatty(fd);
}
void Abort(void){
pfmt(err, "aborting\n");
flush(err);
Exit("aborting");
}
void Memcpy(char *a, char *b, long n)
{
memmove(a, b, (long)n);
}
void *Malloc(ulong n){
return malloc(n);
}
int
exitcode(char *msg)
{
int n;
n = atoi(msg);
if(n == 0)
n = 1;
return n;
}
int *waitpids;
int nwaitpids;
void
addwaitpid(int pid)
{
waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
if(waitpids == 0)
panic("Can't realloc %d waitpids", nwaitpids+1);
waitpids[nwaitpids++] = pid;
}
void
delwaitpid(int pid)
{
int r, w;
for(r=w=0; r<nwaitpids; r++)
if(waitpids[r] != pid)
waitpids[w++] = waitpids[r];
nwaitpids = w;
}
void
clearwaitpids(void)
{
nwaitpids = 0;
}
int
havewaitpid(int pid)
{
int i;
for(i=0; i<nwaitpids; i++)
if(waitpids[i] == pid)
return 1;
return 0;
}