2003-11-23 18:04:08 +00:00
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
{
|
2004-03-25 23:03:57 +00:00
|
|
|
return unsharp("#9/rcmain");
|
2003-11-23 18:04:08 +00:00
|
|
|
}
|
|
|
|
|
2004-03-25 23:03:57 +00:00
|
|
|
char Fdprefix[]="/dev/fd/";
|
2003-11-23 18:04:08 +00:00
|
|
|
void execfinit(void);
|
|
|
|
void execbind(void);
|
|
|
|
void execmount(void);
|
2004-10-17 05:19:53 +00:00
|
|
|
void execulimit(void);
|
|
|
|
void execumask(void);
|
2003-11-23 18:04:08 +00:00
|
|
|
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,
|
2004-10-17 05:19:53 +00:00
|
|
|
"ulimit", execulimit,
|
|
|
|
"umask", execumask,
|
2003-11-23 18:04:08 +00:00
|
|
|
0
|
|
|
|
};
|
|
|
|
#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':
|
2004-05-11 17:51:27 +00:00
|
|
|
// pfmt(err, "rc: odd environment %q?\n", *env);
|
2003-11-23 18:04:08 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
int Waitfor(int pid, int unused0){
|
|
|
|
thread *p;
|
|
|
|
Waitmsg *w;
|
|
|
|
char errbuf[ERRMAX];
|
|
|
|
|
|
|
|
while((w = wait()) != nil){
|
|
|
|
if(w->pid==pid){
|
|
|
|
setstatus(w->msg);
|
|
|
|
free(w);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
for(p=runq->ret;p;p=p->ret)
|
|
|
|
if(p->pid==w->pid){
|
|
|
|
p->pid=-1;
|
|
|
|
strcpy(p->status, w->msg);
|
|
|
|
}
|
|
|
|
free(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
errstr(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
|
2004-03-26 01:59:35 +00:00
|
|
|
cmpenv(const void *a, const void *b)
|
2003-11-23 18:04:08 +00:00
|
|
|
{
|
2004-03-26 01:59:35 +00:00
|
|
|
return strcmp(*(char**)a, *(char**)b);
|
2003-11-23 18:04:08 +00:00
|
|
|
}
|
|
|
|
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 n;
|
|
|
|
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;
|
2003-12-03 22:50:48 +00:00
|
|
|
for(i=0;syssigname[i];i++)
|
|
|
|
if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
|
2004-03-26 17:30:36 +00:00
|
|
|
if(strncmp(s, "sys: ", 5)!=0){
|
|
|
|
if(kidpid && !interrupted){
|
|
|
|
interrupted=1;
|
|
|
|
postnote(PNGROUP, kidpid, s);
|
|
|
|
}
|
|
|
|
interrupted = 1;
|
|
|
|
}
|
2003-12-03 22:50:48 +00:00
|
|
|
goto Out;
|
|
|
|
}
|
2004-03-04 02:36:36 +00:00
|
|
|
if(strcmp(s, "sys: child") != 0)
|
|
|
|
pfmt(err, "rc: note: %s\n", s);
|
2003-11-23 18:04:08 +00:00
|
|
|
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)
|
|
|
|
{
|
2003-12-03 22:50:48 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
i = read(fd, buf, cnt);
|
|
|
|
if(ntrap) dotrap();
|
|
|
|
return i;
|
2003-11-23 18:04:08 +00:00
|
|
|
}
|
|
|
|
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 unused0){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
void Exit(char *stat)
|
|
|
|
{
|
|
|
|
Updenv();
|
|
|
|
setstatus(stat);
|
|
|
|
exits(truestatus()?"":getstatus());
|
|
|
|
}
|
|
|
|
int Eintr(void){
|
|
|
|
return interrupted;
|
|
|
|
}
|
|
|
|
void Noerror(void){
|
|
|
|
interrupted=0;
|
|
|
|
}
|
|
|
|
int
|
2004-03-26 01:59:35 +00:00
|
|
|
Isatty(int fd){
|
2003-11-23 18:04:08 +00:00
|
|
|
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);
|
|
|
|
}
|