/* * Expand and glob the words after an i/o redirection. * If more than one word is generated, then update the command vector. * * This is done differently in all the shells: * 1. in the bourne shell and ksh globbing is not performed * 2. Bash/csh say ambiguous * 3. zsh does i/o to/from all the files * 4. itcsh concatenates the words. * * I don't know what is best to do. I think that Ambiguous is better * than restructuring the command vector, because the user can get * unexpected results. In any case, the command vector restructuring * code is present and the user can choose it by setting noambiguous */ static Char * splicepipe(struct command *t, Char *cp) { Char *blk[2]; if (adrof(STRnoambiguous)) { Char **pv; int gflag; blk[0] = Dfix1(cp); /* expand $ */ blk[1] = NULL; gflag = tglob(blk); if (gflag) { pv = globall(blk, gflag); if (pv == NULL) { setname(short2str(blk[0])); xfree(blk[0]); stderror(ERR_NAME | ERR_NOMATCH); } if (pv[1] != NULL) { /* we need to fix the command vector */ Char **av = blkspl(t->t_dcom, &pv[1]); xfree(t->t_dcom); t->t_dcom = av; } xfree(blk[0]); blk[0] = pv[0]; xfree(pv); } } else { Char *buf; buf = Dfix1(cp); cleanup_push(buf, xfree); blk[0] = globone(buf, G_ERROR); cleanup_until(buf); } return(blk[0]); }
/* * Expand and glob the words after an i/o redirection. * If more than one word is generated, then update the command vector. * * This is done differently in all the shells: * 1. in the bourne shell and ksh globbing is not performed * 2. Bash/csh say ambiguous * 3. zsh does i/o to/from all the files * 4. itcsh concatenates the words. * * I don't know what is best to do. I think that Ambiguous is better * than restructuring the command vector, because the user can get * unexpected results. In any case, the command vector restructuring * code is present and the user can choose it by setting noambiguous */ static Char * splicepipe(struct command *t, Char *cp /* word after < or > */) { Char *blk[2]; if (adrof(STRnoambiguous)) { Char **pv; blk[0] = Dfix1(cp); /* expand $ */ blk[1] = NULL; gflag = 0, tglob(blk); if (gflag) { pv = globall(blk); if (pv == NULL) { setname(vis_str(blk[0])); xfree((ptr_t) blk[0]); stderror(ERR_NAME | ERR_NOMATCH); /* NOTREACHED */ } gargv = NULL; if (pv[1] != NULL) { /* we need to fix the command vector */ Char **av = blkspl(t->t_dcom, &pv[1]); xfree((ptr_t) t->t_dcom); t->t_dcom = av; } xfree((ptr_t) blk[0]); blk[0] = pv[0]; xfree((ptr_t) pv); } } else { blk[0] = globone(blk[1] = Dfix1(cp), G_ERROR); xfree((ptr_t) blk[1]); } return(blk[0]); }
/* * Execute command f, arg list t. * Record error message if not found. * Also do shell scripts here. */ static void texec(Char *sf, Char **st) { struct varent *v; Char *lastsh[2], **vp, *st0, **ost; char *f, **t; int fd; unsigned char c = '\0'; /* The order for the conversions is significant */ t = short2blk(st); f = short2str(sf); Vt = t; errno = 0; /* don't use a previous error */ (void)execve(f, t, environ); Vt = 0; blkfree((Char **)t); switch (errno) { case ENOEXEC: /* * From: [email protected] (Casper H.S. Dik) If we could not execute * it, don't feed it to the shell if it looks like a binary! */ if ((fd = open(f, O_RDONLY)) != -1) { if (read(fd, (char *)&c, 1) == 1) { if (!Isprint(c) && (c != '\n' && c != '\t')) { (void)close(fd); /* * We *know* what ENOEXEC means. */ stderror(ERR_ARCH, f, strerror(errno)); } } #ifdef _PATH_BSHELL else c = '#'; #endif (void)close(fd); } /* * If there is an alias for shell, then put the words of the alias in * front of the argument list replacing the command name. Note no * interpretation of the words at this point. */ v = adrof1(STRshell, &aliases); if (v == 0) { vp = lastsh; vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH; vp[1] = NULL; #ifdef _PATH_BSHELL if (fd != -1 && c != '#') vp[0] = STR_BSHELL; #endif } else vp = v->vec; st0 = st[0]; st[0] = sf; ost = st; st = blkspl(vp, st); /* Splice up the new arglst */ ost[0] = st0; sf = *st; /* The order for the conversions is significant */ t = short2blk(st); f = short2str(sf); free(st); Vt = t; (void)execve(f, t, environ); Vt = 0; blkfree((Char **)t); /* FALLTHROUGH */ case ENOMEM: stderror(ERR_SYSTEM, f, strerror(errno)); /* NOTREACHED */ case ENOENT: break; default: if (exerr == 0) { exerr = strerror(errno); if (expath) free(expath); expath = Strsave(sf); Vexpath = expath; } } }
void /*ARGSUSED*/ doexec(Char **v, struct command *t) { struct varent *pathv; Char *blk[2], **av, *dp, **pv, *sav; int i, hashval, hashval1; sigset_t nsigset; int slash; hashval = 0; /* * Glob the command name. We will search $path even if this does something, * as in sh but not in csh. One special case: if there is no PATH, then we * execute only commands which start with '/'. */ blk[0] = t->t_dcom[0]; blk[1] = 0; gflag = 0, tglob(blk); if (gflag) { pv = globall(blk); if (pv == 0) { setname(vis_str(blk[0])); stderror(ERR_NAME | ERR_NOMATCH); } gargv = 0; } else pv = saveblk(blk); trim(pv); exerr = 0; expath = Strsave(pv[0]); Vexpath = expath; pathv = adrof(STRpath); if (pathv == 0 && expath[0] != '/') { blkfree(pv); pexerr(); } slash = any(short2str(expath), '/'); /* * Glob the argument list, if necessary. Otherwise trim off the quote bits. */ gflag = 0; av = &t->t_dcom[1]; tglob(av); if (gflag) { av = globall(av); if (av == 0) { blkfree(pv); setname(vis_str(expath)); stderror(ERR_NAME | ERR_NOMATCH); } gargv = 0; } else av = saveblk(av); blkfree(t->t_dcom); t->t_dcom = blkspl(pv, av); free(pv); free(av); av = t->t_dcom; trim(av); if (*av == NULL || **av == '\0') pexerr(); xechoit(av); /* Echo command if -x */ /* * Since all internal file descriptors are set to close on exec, we don't * need to close them explicitly here. Just reorient ourselves for error * messages. */ SHIN = 0; SHOUT = 1; SHERR = 2; OLDSTD = 0; /* * We must do this AFTER any possible forking (like `foo` in glob) so that * this shell can still do subprocesses. */ sigemptyset(&nsigset); (void)sigprocmask(SIG_SETMASK, &nsigset, NULL); /* * If no path, no words in path, or a / in the filename then restrict the * command search. */ if (pathv == 0 || pathv->vec[0] == 0 || slash) pv = justabs; else pv = pathv->vec; sav = Strspl(STRslash, *av); /* / command name for postpending */ Vsav = sav; if (havhash) hashval = hashname(*av); i = 0; hits++; do { /* * Try to save time by looking at the hash table for where this command * could be. If we are doing delayed hashing, then we put the names in * one at a time, as the user enters them. This is kinda like Korn * Shell's "tracked aliases". */ if (!slash && pv[0][0] == '/' && havhash) { hashval1 = hash(hashval, i); if (!bit(xhash, hashval1)) goto cont; } if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ texec(*av, av); else { dp = Strspl(*pv, sav); Vdp = dp; texec(dp, av); Vdp = 0; free(dp); } misses++; cont: pv++; i++; } while (*pv); hits--; Vsav = 0; free(sav); pexerr(); /* NOTREACHED */ }
/*VARARGS 1*/ void execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout, int do_glob) { int forked = 0; const struct biltins * volatile bifunc; pid_t pid = 0; int pv[2]; sigset_t set; static sigset_t csigset; #ifdef VFORK static int onosigchld = 0; #endif /* VFORK */ static int nosigchld = 0; (void) &wanttty; (void) &forked; (void) &bifunc; if (t == 0) return; #ifdef WINNT_NATIVE { if ((varval(STRNTslowexec) == STRNULL) && !t->t_dcdr && !t->t_dcar && !t->t_dflg && !didfds && (intty || intact) && (t->t_dtyp == NODE_COMMAND) && !isbfunc(t)) { if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1); Dfix(t); if (nt_try_fast_exec(t) == 0) return; } } #endif /* WINNT_NATIVE */ /* * Ed [email protected] & Dominic [email protected] * Sat Feb 25 03:13:11 PST 1995 * try implicit cd if we have a 1 word command */ if (implicit_cd && (intty || intact) && t->t_dcom && t->t_dcom[0] && t->t_dcom[0][0] && (blklen(t->t_dcom) == 1) && !noexec) { Char *sCName; struct stat stbuf; char *pathname; sCName = dollar(t->t_dcom[0]); if (sCName != NULL && sCName[0] == '~') { struct Strbuf buf = Strbuf_INIT; const Char *name_end; for (name_end = sCName + 1; *name_end != '\0' && *name_end != '/'; name_end++) continue; if (name_end != sCName + 1) { Char *name, *home; name = Strnsave(sCName + 1, name_end - (sCName + 1)); home = gethdir(name); if (home != NULL) { Strbuf_append(&buf, home); xfree(home); } else Strbuf_append(&buf, name); xfree(name); } else Strbuf_append(&buf, varval(STRhome)); Strbuf_append(&buf, name_end); xfree(sCName); sCName = Strbuf_finish(&buf); } pathname = short2str(sCName); xfree(sCName); /* if this is a dir, tack a "cd" on as the first arg */ if (pathname != NULL && ((stat(pathname, &stbuf) != -1 && S_ISDIR(stbuf.st_mode)) #ifdef WINNT_NATIVE || (pathname[0] && pathname[1] == ':' && pathname[2] == '\0') #endif /* WINNT_NATIVE */ )) { Char *vCD[2]; Char **ot_dcom = t->t_dcom; vCD[0] = Strsave(STRcd); vCD[1] = NULL; t->t_dcom = blkspl(vCD, ot_dcom); xfree(ot_dcom); if (implicit_cd > 1) { blkpr(t->t_dcom); xputchar( '\n' ); } } } /* * From: Michael Schroeder <*****@*****.**> * Don't check for wantty > 0... */ if (t->t_dflg & F_AMPERSAND) wanttty = 0; switch (t->t_dtyp) { case NODE_COMMAND: if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) memmove(t->t_dcom[0], t->t_dcom[0] + 1, (Strlen(t->t_dcom[0] + 1) + 1) * sizeof (*t->t_dcom[0])); if ((t->t_dflg & F_REPEAT) == 0) Dfix(t); /* $ " ' \ */ if (t->t_dcom[0] == 0) { return; } /*FALLTHROUGH*/ case NODE_PAREN: #ifdef BACKPIPE if (t->t_dflg & F_PIPEIN) mypipe(pipein); #else /* !BACKPIPE */ if (t->t_dflg & F_PIPEOUT) mypipe(pipeout); #endif /* BACKPIPE */ /* * Must do << early so parent will know where input pointer should be. * If noexec then this is all we do. */ if (t->t_dflg & F_READ) { xclose(0); heredoc(t->t_dlef); if (noexec) xclose(0); } setcopy(STRstatus, STR0, VAR_READWRITE); /* * This mess is the necessary kludge to handle the prefix builtins: * nice, nohup, time. These commands can also be used by themselves, * and this is not handled here. This will also work when loops are * parsed. */ while (t->t_dtyp == NODE_COMMAND) if (eq(t->t_dcom[0], STRnice)) { if (t->t_dcom[1]) { if (strchr("+-", t->t_dcom[1][0])) { if (t->t_dcom[2]) { setname("nice"); t->t_nice = (unsigned char)getn(t->t_dcom[1]); lshift(t->t_dcom, 2); t->t_dflg |= F_NICE; } else break; } else { t->t_nice = 4; lshift(t->t_dcom, 1); t->t_dflg |= F_NICE; } } else break; } else if (eq(t->t_dcom[0], STRnohup)) { if (t->t_dcom[1]) { t->t_dflg |= F_NOHUP; lshift(t->t_dcom, 1); } else break; } else if (eq(t->t_dcom[0], STRhup)) { if (t->t_dcom[1]) { t->t_dflg |= F_HUP; lshift(t->t_dcom, 1); } else break; } else if (eq(t->t_dcom[0], STRtime)) { if (t->t_dcom[1]) { t->t_dflg |= F_TIME; lshift(t->t_dcom, 1); } else break; } #ifdef F_VER else if (eq(t->t_dcom[0], STRver)) if (t->t_dcom[1] && t->t_dcom[2]) { setname("ver"); t->t_systype = getv(t->t_dcom[1]); lshift(t->t_dcom, 2); t->t_dflg |= F_VER; } else break; #endif /* F_VER */ else break; /* is it a command */ if (t->t_dtyp == NODE_COMMAND) { /* * Check if we have a builtin function and remember which one. */ bifunc = isbfunc(t); if (noexec) { /* * Continue for builtins that are part of the scripting language */ if (bifunc == NULL) break; if (bifunc->bfunct != (bfunc_t)dobreak && bifunc->bfunct != (bfunc_t)docontin && bifunc->bfunct != (bfunc_t)doelse && bifunc->bfunct != (bfunc_t)doend && bifunc->bfunct != (bfunc_t)doforeach&& bifunc->bfunct != (bfunc_t)dogoto && bifunc->bfunct != (bfunc_t)doif && bifunc->bfunct != (bfunc_t)dorepeat && bifunc->bfunct != (bfunc_t)doswbrk && bifunc->bfunct != (bfunc_t)doswitch && bifunc->bfunct != (bfunc_t)dowhile && bifunc->bfunct != (bfunc_t)dozip) break; } } else { /* not a command */ bifunc = NULL; if (noexec) break; } /* * GrP Executing a command - run jobcmd hook * Don't run for builtins * Don't run if we're not in a tty * Don't run if we're not really executing */ /* * CR - Charles Ross Aug 2005 * added "isoutatty". * The new behavior is that the jobcmd won't be executed * if stdout (SHOUT) isnt attached to a tty.. IE when * redirecting, or using backquotes etc.. */ if (t->t_dtyp == NODE_COMMAND && !bifunc && !noexec && intty && isoutatty) { Char *cmd = unparse(t); cleanup_push(cmd, xfree); job_cmd(cmd); cleanup_until(cmd); } /* * We fork only if we are timed, or are not the end of a parenthesized * list and not a simple builtin function. Simple meaning one that is * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not * fork in some of these cases. */ #ifdef BACKPIPE /* * Can't have NOFORK for the tail of a pipe - because it is not the * last command spawned (even if it is at the end of a parenthesised * list). */ if (t->t_dflg & F_PIPEIN) t->t_dflg &= ~(F_NOFORK); #else /* * "command | builtin" may cause major misbehaviour as noted in * in the BUGS file entry * Subject: Redirected input to built-in functions misbehaves badly * forking when the builtin is the end of the pipe corrects the * problem. */ if (bifunc && (t->t_dflg & F_PIPEIN)) t->t_dflg &= ~(F_NOFORK); #endif /* BACKPIPE */ /* * Prevent forking cd, pushd, popd, chdir cause this will cause the * shell not to change dir! (XXX: but only for nice?) */ if (bifunc && (bifunc->bfunct == (bfunc_t)dochngd || bifunc->bfunct == (bfunc_t)dopushd || bifunc->bfunct == (bfunc_t)dopopd)) t->t_dflg &= ~(F_NICE); if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 && (!bifunc || t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP | F_HUP)))) || /* * We have to fork for eval too. */ (bifunc && (t->t_dflg & F_PIPEIN) != 0 && bifunc->bfunct == (bfunc_t)doeval)) { #ifdef VFORK if (t->t_dtyp == NODE_PAREN || t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) #endif /* VFORK */ { forked++; /* * We need to block SIGCHLD here, so that if the process does * not die before we can set the process group */ if (wanttty >= 0 && !nosigchld) { sigemptyset(&set); sigaddset(&set, SIGCHLD); (void)sigprocmask(SIG_BLOCK, &set, &csigset); nosigchld = 1; } pid = pfork(t, wanttty); if (pid == 0 && nosigchld) { sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } else if (pid != 0 && (t->t_dflg & F_AMPERSAND)) backpid = pid; } #ifdef VFORK else { int ochild, osetintr, ohaderr, odidfds; int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp; int oisoutatty, oisdiagatty; sigset_t oset, ocsigset; # ifndef CLOSE_ON_EXEC int odidcch; # endif /* !CLOSE_ON_EXEC */ /* * Prepare for the vfork by saving everything that the child * corrupts before it exec's. Note that in some signal * implementations which keep the signal info in user space * (e.g. Sun's) it will also be necessary to save and restore * the current sigvec's for the signals the child touches * before it exec's. */ /* * Sooooo true... If this is a Sun, save the sigvec's. (Skip * Gilbrech - 11/22/87) */ # ifdef SAVESIGVEC struct sigaction savesv[NSIGSAVED]; sigset_t savesm; # endif /* SAVESIGVEC */ if (wanttty >= 0 && !nosigchld && !noexec) { sigemptyset(&set); sigaddset(&set, SIGCHLD); (void)sigprocmask(SIG_BLOCK, &set, &csigset); nosigchld = 1; } sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGINT); (void)sigprocmask(SIG_BLOCK, &set, &oset); ochild = child; osetintr = setintr; ohaderr = haderr; odidfds = didfds; # ifndef CLOSE_ON_EXEC odidcch = didcch; # endif /* !CLOSE_ON_EXEC */ oSHIN = SHIN; oSHOUT = SHOUT; oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp; oisoutatty = isoutatty; oisdiagatty = isdiagatty; ocsigset = csigset; onosigchld = nosigchld; Vsav = Vdp = 0; Vexpath = 0; Vt = 0; # ifdef SAVESIGVEC savesigvec(savesv, savesm); # endif /* SAVESIGVEC */ if (use_fork) pid = fork(); else pid = vfork(); if (pid < 0) { # ifdef SAVESIGVEC restoresigvec(savesv, savesm); # endif /* SAVESIGVEC */ sigprocmask(SIG_SETMASK, &oset, NULL); stderror(ERR_NOPROC); } forked++; if (pid) { /* parent */ # ifdef SAVESIGVEC restoresigvec(savesv, savesm); # endif /* SAVESIGVEC */ child = ochild; setintr = osetintr; haderr = ohaderr; didfds = odidfds; SHIN = oSHIN; # ifndef CLOSE_ON_EXEC didcch = odidcch; # endif /* !CLOSE_ON_EXEC */ SHOUT = oSHOUT; SHDIAG = oSHDIAG; OLDSTD = oOLDSTD; tpgrp = otpgrp; isoutatty = oisoutatty; isdiagatty = oisdiagatty; csigset = ocsigset; nosigchld = onosigchld; xfree(Vsav); Vsav = 0; xfree(Vdp); Vdp = 0; xfree(Vexpath); Vexpath = 0; blk_cleanup(Vt); Vt = 0; /* this is from pfork() */ palloc(pid, t); sigprocmask(SIG_SETMASK, &oset, NULL); } else { /* child */ /* this is from pfork() */ pid_t pgrp; int ignint = 0; if (nosigchld) { sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } if (setintr) ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) || (gointr && eq(gointr, STRminus)); pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); child++; if (setintr) { setintr = 0; /* * casts made right for SunOS 4.0 by Douglas C. Schmidt * <*****@*****.**> * (thanks! -- PWP) * * ignint ifs cleaned by Johan Widen <[email protected]> * (thanks again) */ if (ignint) { (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); } else { (void) signal(SIGINT, vffree); (void) signal(SIGQUIT, SIG_DFL); } # ifdef BSDJOBS if (wanttty >= 0) { (void) signal(SIGTSTP, SIG_DFL); (void) signal(SIGTTIN, SIG_DFL); (void) signal(SIGTTOU, SIG_DFL); } # endif /* BSDJOBS */ sigaction(SIGTERM, &parterm, NULL); } else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); } pgetty(wanttty, pgrp); if (t->t_dflg & F_NOHUP) (void) signal(SIGHUP, SIG_IGN); if (t->t_dflg & F_HUP) (void) signal(SIGHUP, SIG_DFL); if (t->t_dflg & F_NICE) { int nval = SIGN_EXTEND_CHAR(t->t_nice); # if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS) if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno) stderror(ERR_SYSTEM, "setpriority", strerror(errno)); # else /* !HAVE_SETPRIORITY || !PRIO_PROCESS */ (void) nice(nval); # endif /* HAVE_SETPRIORITY && PRIO_PROCESS */ } # ifdef F_VER if (t->t_dflg & F_VER) { tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); dohash(NULL, NULL); } # endif /* F_VER */ } } #endif /* VFORK */ } if (pid != 0) { /* * It would be better if we could wait for the whole job when we * knew the last process had been started. Pwait, in fact, does * wait for the whole job anyway, but this test doesn't really * express our intentions. */ #ifdef BACKPIPE if (didfds == 0 && t->t_dflg & F_PIPEOUT) { xclose(pipeout[0]); xclose(pipeout[1]); } if ((t->t_dflg & F_PIPEIN) != 0) break; #else /* !BACKPIPE */ if (didfds == 0 && t->t_dflg & F_PIPEIN) { xclose(pipein[0]); xclose(pipein[1]); } if ((t->t_dflg & F_PIPEOUT) != 0) break; #endif /* BACKPIPE */ if (nosigchld) { sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } if ((t->t_dflg & F_AMPERSAND) == 0) pwait(); break; } doio(t, pipein, pipeout); #ifdef BACKPIPE if (t->t_dflg & F_PIPEIN) { xclose(pipein[0]); xclose(pipein[1]); } #else /* !BACKPIPE */ if (t->t_dflg & F_PIPEOUT) { xclose(pipeout[0]); xclose(pipeout[1]); } #endif /* BACKPIPE */ /* * Perform a builtin function. If we are not forked, arrange for * possible stopping */ if (bifunc) { if (forked) { func(t, bifunc); exitstat(); } else { jmp_buf_t oldexit; int ohaderr = haderr; getexit(oldexit); if (setexit() == 0) func(t, bifunc); resexit(oldexit); haderr = ohaderr; if (adrof(STRprintexitvalue)) { int rv = getn(varval(STRstatus)); if (rv != 0) xprintf(CGETS(17, 2, "Exit %d\n"), rv); } } break; } if (t->t_dtyp != NODE_PAREN) { doexec(t, do_glob); /* NOTREACHED */ } /* * For () commands must put new 0,1,2 in FSH* and recurse */ if ((OLDSTD = dcopy(0, FOLDSTD)) >= 0) (void)close_on_exec(OLDSTD, 1); if ((SHOUT = dcopy(1, FSHOUT)) >= 0) { (void)close_on_exec(SHOUT, 1); isoutatty = isatty(SHOUT); } if ((SHDIAG = dcopy(2, FSHDIAG)) >= 0) { (void)close_on_exec(SHDIAG, 1); isdiagatty = isatty(SHDIAG); } xclose(SHIN); SHIN = -1; #ifndef CLOSE_ON_EXEC didcch = 0; #else (void) close_on_exec(FSHOUT, 1); (void) close_on_exec(FSHDIAG, 1); (void) close_on_exec(FOLDSTD, 1); #endif /* !CLOSE_ON_EXEC */ didfds = 0; wanttty = -1; t->t_dspr->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); execute(t->t_dspr, wanttty, NULL, NULL, do_glob); exitstat(); case NODE_PIPE: #ifdef BACKPIPE t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcdr, wanttty, pv, pipeout, do_glob); t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcar, wanttty, pipein, pv, do_glob); #else /* !BACKPIPE */ t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcar, wanttty, pipein, pv, do_glob); t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcdr, wanttty, pv, pipeout, do_glob); #endif /* BACKPIPE */ break; case NODE_LIST: if (t->t_dcar) { t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); execute(t->t_dcar, wanttty, NULL, NULL, do_glob); /* * In strange case of A&B make a new job after A */ if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr && (t->t_dcdr->t_dflg & F_AMPERSAND) == 0) pendjob(); } if (t->t_dcdr) { t->t_dcdr->t_dflg |= t->t_dflg & (F_NOFORK | F_NOINTERRUPT | F_BACKQ); execute(t->t_dcdr, wanttty, NULL, NULL, do_glob); } break; case NODE_OR: case NODE_AND: if (t->t_dcar) { t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); execute(t->t_dcar, wanttty, NULL, NULL, do_glob); if ((getn(varval(STRstatus)) == 0) != (t->t_dtyp == NODE_AND)) { return; } } if (t->t_dcdr) { t->t_dcdr->t_dflg |= t->t_dflg & (F_NOFORK | F_NOINTERRUPT | F_BACKQ); execute(t->t_dcdr, wanttty, NULL, NULL, do_glob); } break; default: break; } /* * Fall through for all breaks from switch * * If there will be no more executions of this command, flush all file * descriptors. Places that turn on the F_REPEAT bit are responsible for * doing donefds after the last re-execution */ if (didfds && !(t->t_dflg & F_REPEAT)) donefds(); }
int nt_try_fast_exec(struct command *t) { register Char **pv, **av; register Char *dp,*sav; register char **tt; register char *f; register struct varent *v; register int hashval,i; register int slash; int rc = 0, gflag; Char *vp; Char *blk[2]; vp = varval(STRNTslowexec); if (vp != STRNULL) return 1; blk[0] = t->t_dcom[0]; blk[1] = 0; // don't do backtick if(Strchr(t->t_dcom[0],'`') ) return 1; gflag = tglob(blk); if (gflag) { pv = globall(blk, gflag); if (pv == 0) { return 1; } } else pv = saveblk(blk); trim(pv); epath = Strsave(pv[0]); v = adrof(STRpath); if (v == 0 && epath[0] != '/' && epath[0] != '.') { blkfree(pv); return 1; } slash = any(short2str(epath),'/'); /* * Glob the argument list, if necessary. Otherwise trim off the quote bits. */ av = &t->t_dcom[1]; gflag = tglob(av); if (gflag) { av = globall(av, gflag);/*FIXRESET*/ if (av == 0) { blkfree(pv); return 1; } } else av = saveblk(av); blkfree(t->t_dcom); t->t_dcom = blkspl(pv, av); xfree((ptr_t) pv); xfree((ptr_t) av); av = t->t_dcom; //trim(av); if (*av == NULL || **av == '\0') return 1; xechoit(av);/*FIXRESET*/ /* Echo command if -x */ if (v == 0 || v->vec[0] == 0 || slash) pv = abspath; else pv = v->vec; sav = Strspl(STRslash,*av); hashval = hashval_extern(*av); i = 0; do { #pragma warning(disable:4310) if (!slash && ABSOLUTEP(pv[0]) && havhash) { #pragma warning(default:4310) if (!bit_extern(hashval,i)){ pv++;i++; continue; } } if (pv[0][0] == 0 || eq(pv[0],STRdot)) { tt = short2blk(av); f = short2str(*av); rc = nt_texec(f, tt); blkfree((Char**)tt); if (!rc) break; } else { dp = Strspl(*pv,sav); tt = short2blk(av); f = short2str(dp); rc = nt_texec(f, tt); blkfree((Char**)tt); xfree((ptr_t)dp); if (!rc) break; } pv++; i++; }while(*pv); return rc; }
void doexec(struct command *t) { tchar *sav; tchar *dp, **pv, **av; struct varent *v; bool slash; int hashval, hashval1, i; tchar *blk[2]; #ifdef TRACE tprintf("TRACE- doexec()\n"); #endif /* * Glob the command name. If this does anything, then we * will execute the command only relative to ".". One special * case: if there is no PATH, then we execute only commands * which start with '/'. */ dp = globone(t->t_dcom[0]); sav = t->t_dcom[0]; exerr = 0; t->t_dcom[0] = dp; setname(dp); xfree(sav); v = adrof(S_path /* "path" */); if (v == 0 && dp[0] != '/') { pexerr(); } slash = gflag; /* * Glob the argument list, if necessary. * Otherwise trim off the quote bits. */ gflag = 0; av = &t->t_dcom[1]; tglob(av); if (gflag) { av = glob(av); if (av == 0) error("No match"); } blk[0] = t->t_dcom[0]; blk[1] = 0; av = blkspl(blk, av); #ifdef VFORK Vav = av; #endif trim(av); slash |= any('/', av[0]); xechoit(av); /* Echo command if -x */ /* * Since all internal file descriptors are set to close on exec, * we don't need to close them explicitly here. Just reorient * ourselves for error messages. */ SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0; /* * We must do this AFTER any possible forking (like `foo` * in glob) so that this shell can still do subprocesses. */ (void) sigsetmask(0); /* * If no path, no words in path, or a / in the filename * then restrict the command search. */ if (v == 0 || v->vec[0] == 0 || slash) pv = justabs; else pv = v->vec; sav = strspl(S_SLASH /* "/" */, *av); /* / command name for postpending */ #ifdef VFORK Vsav = sav; #endif if (havhash) hashval = hashname(*av); i = 0; #ifdef VFORK hits++; #endif do { if (!slash && pv[0][0] == '/' && havhash) { hashval1 = hash(hashval, i); if (!bit(xhash, hashval1)) goto cont; } if (pv[0][0] == 0 || eq(pv[0], S_DOT /* "." */)) { /* don't make ./xxx */ texec(t, *av, av); } else { dp = strspl(*pv, sav); #ifdef VFORK Vdp = dp; #endif texec(t, dp, av); #ifdef VFORK Vdp = 0; #endif xfree(dp); } #ifdef VFORK misses++; #endif cont: pv++; i++; } while (*pv); #ifdef VFORK hits--; #endif #ifdef VFORK Vsav = 0; Vav = 0; #endif xfree(sav); xfree((char *)av); pexerr(); }
/* * Execute command f, arg list t. * Record error message if not found. * Also do shell scripts here. */ void texec(struct command *cmd, tchar *f, tchar **t) { int pfstatus = 0; struct varent *v; tchar **vp; tchar *lastsh[2]; #ifdef TRACE tprintf("TRACE- texec()\n"); #endif /* convert cfname and cargs from tchar to char */ tconvert(cmd, f, t); if (pfcshflag == 1) { pfstatus = secpolicy_pfexec((const char *)(cmd->cfname), cmd->cargs, (const char **)NULL); if (pfstatus != NOATTRS) { errno = pfstatus; } } if ((pfcshflag == 0) || (pfstatus == NOATTRS)) { execv(cmd->cfname, cmd->cargs); } /* * exec returned, free up allocations from above * tconvert(), zero cfname and cargs to prevent * duplicate free() in freesyn() */ xfree(cmd->cfname); chr_blkfree(cmd->cargs); cmd->cfname = (char *)0; cmd->cargs = (char **)0; switch (errno) { case ENOEXEC: /* check that this is not a binary file */ { int ff = open_(f, 0); tchar ch[MB_LEN_MAX]; if (ff != -1 && read_(ff, ch, 1) == 1 && !isprint(ch[0]) && !isspace(ch[0])) { printf("Cannot execute binary file.\n"); Perror(f); (void) close(ff); unsetfd(ff); return; } (void) close(ff); unsetfd(ff); } /* * If there is an alias for shell, then * put the words of the alias in front of the * argument list replacing the command name. * Note no interpretation of the words at this point. */ v = adrof1(S_shell /* "shell" */, &aliases); if (v == 0) { #ifdef OTHERSH int ff = open_(f, 0); tchar ch[MB_LEN_MAX]; #endif vp = lastsh; vp[0] = adrof(S_shell /* "shell" */) ? value(S_shell /* "shell" */) : S_SHELLPATH /* SHELLPATH */; vp[1] = (tchar *) NULL; #ifdef OTHERSH if (ff != -1 && read_(ff, ch, 1) == 1 && ch[0] != '#') vp[0] = S_OTHERSH /* OTHERSH */; (void) close(ff); unsetfd(ff); #endif } else vp = v->vec; t[0] = f; t = blkspl(vp, t); /* Splice up the new arglst */ f = *t; tconvert(cmd, f, t); /* convert tchar to char */ /* * now done with tchar arg list t, * free the space calloc'd by above blkspl() */ xfree((char *)t); execv(cmd->cfname, cmd->cargs); /* exec the command */ /* exec returned, same free'ing as above */ xfree(cmd->cfname); chr_blkfree(cmd->cargs); cmd->cfname = (char *)0; cmd->cargs = (char **)0; /* The sky is falling, the sky is falling! */ case ENOMEM: Perror(f); case ENOENT: break; default: if (exerr == 0) { exerr = strerror(errno); setname(f); } } }