plan9fox/sys/src/cmd/rc/win32.c
cinap_lenrek 258fe87faf rc: terminate rc when exec fails, cleanup
The execexec() function should never return, as it irreversably changes
the filedescriptor table for the new program. This means rc's internal
filedesciptors for reading the script get implicitely closed and we cannot
continue the rc interpreter when Execute() fails. So Execute() now sets the
error status, and execexec() runs Xexit() in case Execute() returns.
2016-02-22 22:25:21 +01:00

567 lines
8.6 KiB
C

/*
* 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[]="/rc/lib/rcmain";
char Fdprefix[]="/fd/";
void execfinit(void);
void execbind(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,
0
};
void
Vinit(void)
{
int dir, f, len;
word *val;
char *buf, *s;
Dir *ent;
int i, nent;
char envname[256];
dir = open("/env", OREAD);
if(dir<0){
pfmt(err, "rc: can't open /env: %r\n");
return;
}
ent = nil;
for(;;){
nent = dirread(dir, &ent);
if(nent <= 0)
break;
for(i = 0; i<nent; i++){
len = ent[i].length;
if(len && strncmp(ent[i].name, "fn#", 3)!=0){
snprint(envname, sizeof envname, "/env/%s", ent[i].name);
if((f = open(envname, 0))>=0){
buf = emalloc((int)len+1);
read(f, buf, (long)len);
val = 0;
/* Charitably add a 0 at the end if need be */
if(buf[len-1])
buf[len++]='\0';
s = buf+len-1;
for(;;){
while(s!=buf && s[-1]!='\0') --s;
val = newword(s, val);
if(s==buf)
break;
--s;
}
setvar(ent[i].name, val);
vlook(ent[i].name)->changed = 0;
close(f);
efree(buf);
}
}
}
free(ent);
}
close(dir);
}
int envdir;
void
Xrdfn(void)
{
int f, len;
static Dir *ent, *allocent;
static int nent;
Dir *e;
char envname[256];
for(;;){
if(nent == 0){
free(allocent);
nent = dirread(envdir, &allocent);
ent = allocent;
}
if(nent <= 0)
break;
while(nent){
e = ent++;
nent--;
len = e->length;
if(len && strncmp(e->name, "fn#", 3)==0){
snprint(envname, sizeof envname, "/env/%s", e->name);
if((f = open(envname, 0))>=0){
execcmds(openfd(f));
return;
}
}
}
}
close(envdir);
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();
envdir = open("/env", 0);
if(envdir<0){
pfmt(err, "rc: can't open /env: %r\n");
return;
}
start(rdfns, 1, runq->local);
}
int
Waitfor(int pid, int persist)
{
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 %q %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
ForkExecute(char *file, char **argv, int sin, int sout, int serr)
{
int pid;
{int i;
fprint(2, "forkexec %s", file);
for(i = 0; argv[i]; i++)fprint(2, " %s", argv[i]);
fprint(2, " %d %d %d\n", sin, sout, serr);
}
if(access(file, 1) != 0)
return -1;
fprint(2, "forking\n");
switch(pid = fork()){
case -1:
return -1;
case 0:
if(sin >= 0)
dup(sin, 0);
else
close(0);
if(sout >= 0)
dup(sout, 1);
else
close(1);
if(serr >= 0)
dup(serr, 2);
else
close(2);
fprint(2, "execing\n");
exec(file, argv);
fprint(2, "exec: %r\n");
exits(file);
}
return pid;
}
void
Execute(word *args, word *path)
{
char **argv = mkargv(args);
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]);
exec(file, argv+1);
}
else werrstr("command name too long");
}
}
rerrstr(file, sizeof file);
setstatus(file);
pfmt(err, "%s: %s\n", argv[1], file);
efree((char *)argv);
}
#define NDIR 256 /* shoud be a better way */
int
Globsize(char *p)
{
int 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;
}
static int
trimdirs(Dir *d, int nd)
{
int r, w;
for(r=w=0; r<nd; r++)
if(d[r].mode&DMDIR)
d[w++] = d[r];
return w;
}
/*
* onlydirs is advisory -- it means you only
* need to return the directories. it's okay to
* return files too (e.g., on unix where you can't
* tell during the readdir), but that just makes
* the globber work harder.
*/
int
Readdir(int f, void *p, int onlydirs)
{
int n;
if(f<0 || f>=NFD)
return 0;
Again:
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){
if(onlydirs){
n = trimdirs(dir[f].dbuf, n);
if(n == 0)
goto Again;
}
dir[f].n = n;
}else
dir[f].n = 0;
dir[f].i = 0;
}
if(dir[f].i == dir[f].n)
return 0;
strncpy(p, dir[f].dbuf[dir[f].i].name, NDIR);
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*, 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) interrupted = 1;
goto Out;
}
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, void *buf, long cnt)
{
return write(fd, buf, (long)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
Creat(char *file)
{
return create(file, 1, 0666L);
}
int
Dup(int a, int b)
{
return dup(a, b);
}
int
Dup1(int)
{
return -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)
{
Dir *d1, *d2;
int ret;
d1 = dirfstat(fd);
if(d1 == nil)
return 0;
if(strncmp(d1->name, "ptty", 4)==0){ /* fwd complaints to philw */
free(d1);
return 1;
}
d2 = dirstat("/dev/cons");
if(d2 == nil){
free(d1);
return 0;
}
ret = (d1->type==d2->type&&d1->dev==d2->dev&&d1->qid.path==d2->qid.path);
free(d1);
free(d2);
return ret;
}
void
Abort(void)
{
pfmt(err, "aborting\n");
flush(err);
Exit("aborting");
}
void
Memcpy(void *a, void *b, long n)
{
memmove(a, b, n);
}
void*
Malloc(ulong n)
{
return malloc(n);
}
void*
Realloc(void *p, ulong n)
{
return realloc(p, n);
}