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.
This commit is contained in:
cinap_lenrek 2016-02-22 22:25:21 +01:00
parent a9639c6894
commit 258fe87faf
7 changed files with 39 additions and 78 deletions

View file

@ -101,7 +101,7 @@ glob(void *ap)
return; return;
} }
globname = emalloc(globlen); globname = emalloc(globlen);
globname[0]='\0'; memset(globname, 0, globlen);
globdir(p, (uchar *)globname); globdir(p, (uchar *)globname);
efree(globname); efree(globname);
if(svglobv==globv){ if(svglobv==globv){

View file

@ -189,32 +189,29 @@ execforkexec(void)
{ {
char **argv; char **argv;
char file[1024]; char file[1024];
int nc; int nc, mc;
word *path; word *path;
int pid; int pid;
if(runq->argv->words==0) if(runq->argv->words==0)
return -1; return -1;
argv = mkargv(runq->argv->words); argv = mkargv(runq->argv->words);
mc = strlen(argv[1])+1;
for(path = searchpath(runq->argv->words->word);path;path = path->next){ for(path = searchpath(runq->argv->words->word);path;path = path->next){
nc = strlen(path->word); nc = strlen(path->word);
if(nc < sizeof file - 1){ /* 1 for / */ if(nc + mc >= sizeof file - 1) /* 1 for / */
strcpy(file, path->word); continue;
if(file[0]){ if(nc > 0){
strcat(file, "/"); memmove(file, path->word, nc);
nc++; file[nc++] = '/';
} }
if(nc+strlen(argv[1])<sizeof(file)){ memmove(file+nc, argv[1], mc);
strcat(file, argv[1]);
pid = ForkExecute(file, argv+1, mapfd(0), mapfd(1), mapfd(2)); pid = ForkExecute(file, argv+1, mapfd(0), mapfd(1), mapfd(2));
if(pid >= 0){ if(pid >= 0){
free(argv); free(argv);
return pid; return pid;
} }
} }
}
}
free(argv); free(argv);
return -1; return -1;
} }

View file

@ -305,72 +305,36 @@ Updenv(void)
/* not used on plan 9 */ /* not used on plan 9 */
int int
ForkExecute(char *file, char **argv, int sin, int sout, int serr) ForkExecute(char *, char **, int, int, int)
{ {
int pid;
if(access(file, 1) != 0)
return -1; return -1;
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);
exec(file, argv);
exits(file);
}
return pid;
} }
void void
Execute(word *args, word *path) Execute(word *args, word *path)
{ {
char **argv = mkargv(args); char **argv = mkargv(args);
char file[1024], errstr[1024]; char file[1024];
int nc; int nc, mc;
Updenv(); Updenv();
errstr[0] = '\0'; mc = strlen(argv[1])+1;
for(;path;path = path->next){ for(;path;path = path->next){
nc = strlen(path->word); nc = strlen(path->word);
if(nc < sizeof file - 1){ /* 1 for / */ if(nc + mc >= sizeof file - 1){ /* 1 for / */
strcpy(file, path->word); werrstr("command path name too long");
if(file[0]){ continue;
strcat(file, "/");
nc++;
} }
if(nc + strlen(argv[1]) < sizeof file){ if(nc > 0){
strcat(file, argv[1]); memmove(file, path->word, nc);
file[nc++] = '/';
}
memmove(file+nc, argv[1], mc);
exec(file, argv+1); exec(file, argv+1);
rerrstr(errstr, sizeof errstr);
/*
* if file exists and is executable, exec should
* have worked, unless it's a directory or an
* executable for another architecture. in
* particular, if it failed due to lack of
* swap/vm (e.g., arg. list too long) or other
* allocation failure, stop searching and print
* the reason for failure.
*/
if (strstr(errstr, " allocat") != nil ||
strstr(errstr, " full") != nil)
break;
} }
else werrstr("command name too long"); rerrstr(file, sizeof file);
} setstatus(file);
} pfmt(err, "%s: %s\n", argv[1], file);
pfmt(err, "%s: %s\n", argv[1], errstr);
efree((char *)argv); efree((char *)argv);
} }
#define NDIR 256 /* shoud be a better way */ #define NDIR 256 /* shoud be a better way */
@ -464,7 +428,7 @@ Again:
} }
if(dir[f].i == dir[f].n) if(dir[f].i == dir[f].n)
return 0; return 0;
strcpy(p, dir[f].dbuf[dir[f].i].name); strncpy((char*)p, dir[f].dbuf[dir[f].i].name, NDIR);
dir[f].i++; dir[f].i++;
return 1; return 1;
} }

View file

@ -55,7 +55,6 @@ Xsimple(void)
/* fork and wait is redundant */ /* fork and wait is redundant */
pushword("exec"); pushword("exec");
execexec(); execexec();
Xexit();
} }
else{ else{
flush(err); flush(err);
@ -120,6 +119,7 @@ execexec(void)
doredir(runq->redir); doredir(runq->redir);
Execute(runq->argv->words, searchpath(runq->argv->words->word)); Execute(runq->argv->words, searchpath(runq->argv->words->word));
poplist(); poplist();
Xexit();
} }
void void

View file

@ -9,15 +9,14 @@ emalloc(long n)
void *p = Malloc(n); void *p = Malloc(n);
if(p==0) if(p==0)
panic("Can't malloc %d bytes", n); panic("Can't malloc %d bytes", n);
/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } /**/
return p; return p;
} }
void* void*
erealloc(void *p, long n) erealloc(void *p, long n)
{ {
p = Realloc(p, n); /* botch, should be Realloc */ p = Realloc(p, n);
if(p==0) if(p==0 && n!=0)
panic("Can't realloc %d bytes\n", n); panic("Can't realloc %d bytes\n", n);
return p; return p;
} }
@ -25,7 +24,6 @@ erealloc(void *p, long n)
void void
efree(void *p) efree(void *p)
{ {
/* pfmt(err, "free %p\n", p); flush(err); /**/
if(p) if(p)
free(p); free(p);
else pfmt(err, "free 0\n"); else pfmt(err, "free 0\n");

View file

@ -275,6 +275,7 @@ register struct word *args, *path;
} }
} }
Bad: Bad:
setstatus(msg);
pfmt(err, "%s: %s\n", argv[1], msg); pfmt(err, "%s: %s\n", argv[1], msg);
efree((char *)env); efree((char *)env);
efree((char *)argv); efree((char *)argv);
@ -319,7 +320,7 @@ int onlydirs; /* ignored, just advisory */
struct direct *dp = readdir(dirlist[f]); struct direct *dp = readdir(dirlist[f]);
if(dp==0) if(dp==0)
return 0; return 0;
strcpy(p, dp->d_name); strncpy(p, dp->d_name, NDIR);
return 1; return 1;
} }
Closedir(f){ Closedir(f){

View file

@ -299,6 +299,7 @@ Execute(word *args, word *path)
} }
} }
rerrstr(file, sizeof file); rerrstr(file, sizeof file);
setstatus(file);
pfmt(err, "%s: %s\n", argv[1], file); pfmt(err, "%s: %s\n", argv[1], file);
efree((char *)argv); efree((char *)argv);
} }
@ -393,7 +394,7 @@ Again:
} }
if(dir[f].i == dir[f].n) if(dir[f].i == dir[f].n)
return 0; return 0;
strcpy(p, dir[f].dbuf[dir[f].i].name); strncpy(p, dir[f].dbuf[dir[f].i].name, NDIR);
dir[f].i++; dir[f].i++;
return 1; return 1;
} }