void source(char *fil, bool okfail) { jmp_buf osetexit; register int saveinp, ointty, oerrno; char *saveglobp; short savepeekc; signal(SIGINT, SIG_IGN); saveinp = dup(0); savepeekc = peekc; saveglobp = globp; peekc = 0; globp = 0; if (saveinp < 0) error("Too many nested sources"); if (slevel <= 0) ttyindes = saveinp; close(0); if (open(fil, O_RDONLY) < 0) { oerrno = errno; setrupt(); dup(saveinp); close(saveinp); errno = oerrno; if (!okfail) filioerr(fil); return; } slevel++; ointty = intty; intty = isatty(0); oprompt = value(PROMPT); value(PROMPT) &= intty; getexit(osetexit); setrupt(); if (setexit() == 0) commands(1, 1); else if (slevel > 1) { close(0); dup(saveinp); close(saveinp); slevel--; resexit(osetexit); reset(); } intty = ointty; value(PROMPT) = oprompt; close(0); dup(saveinp); close(saveinp); globp = saveglobp; peekc = savepeekc; slevel--; resexit(osetexit); }
void fg_proc_entry(struct process *pp) { jmp_buf_t osetexit; int ohaderr; Char oGettingInput; size_t omark; getexit(osetexit); pintr_disabled++; oGettingInput = GettingInput; GettingInput = 0; ohaderr = haderr; /* we need to ignore setting of haderr due to * process getting stopped by a signal */ omark = cleanup_push_mark(); if (setexit() == 0) { /* come back here after pjwait */ pendjob(); (void) alarm(0); /* No autologout */ alrmcatch_disabled = 1; if (!pstart(pp, 1)) { pp->p_procid = 0; stderror(ERR_BADJOB, pp->p_command, strerror(errno)); } pjwait(pp); } setalarm(1); /* Autologout back on */ cleanup_pop_mark(omark); resexit(osetexit); haderr = ohaderr; GettingInput = oGettingInput; disabled_cleanup(&pintr_disabled); }
void alias(struct wordent *lex) { jmp_buf osetexit; aleft = ALEFT; hleft = HLEFT; getexit(osetexit); (void) setexit(); if (haderr) { resexit(osetexit); reset(); } if (--aleft == 0) stderror(ERR_ALIASLOOP); asyntax(lex->next, lex); resexit(osetexit); }
/*ARGSUSED*/ void execash(Char **t, struct command *kp) { jmp_buf osetexit; sig_t osigint, osigquit, osigterm; int my_reenter, odidfds, oOLDSTD, oSHERR, oSHIN, oSHOUT; int saveDIAG, saveIN, saveOUT, saveSTD; if (chkstop == 0 && setintr) panystop(0); /* * Hmm, we don't really want to do that now because we might * fail, but what is the choice */ rechist(); osigint = signal(SIGINT, parintr); osigquit = signal(SIGQUIT, parintr); osigterm = signal(SIGTERM, parterm); odidfds = didfds; oSHIN = SHIN; oSHOUT = SHOUT; oSHERR = SHERR; oOLDSTD = OLDSTD; saveIN = dcopy(SHIN, -1); saveOUT = dcopy(SHOUT, -1); saveDIAG = dcopy(SHERR, -1); saveSTD = dcopy(OLDSTD, -1); lshift(kp->t_dcom, 1); getexit(osetexit); if ((my_reenter = setexit()) == 0) { SHIN = dcopy(0, -1); SHOUT = dcopy(1, -1); SHERR = dcopy(2, -1); didfds = 0; doexec(t, kp); } (void)signal(SIGINT, osigint); (void)signal(SIGQUIT, osigquit); (void)signal(SIGTERM, osigterm); doneinp = 0; didfds = odidfds; (void)close(SHIN); (void)close(SHOUT); (void)close(SHERR); (void)close(OLDSTD); SHIN = dmove(saveIN, oSHIN); SHOUT = dmove(saveOUT, oSHOUT); SHERR = dmove(saveDIAG, oSHERR); OLDSTD = dmove(saveSTD, oOLDSTD); resexit(osetexit); if (my_reenter) stderror(ERR_SILENT); }
/* * Karl Kleinpaste, 21oct1983. * Set up a one-word alias command, for use for special things. * This code is based on the mainline of process(). */ void aliasrun(int cnt, Char *s1, Char *s2) { struct wordent w, *new1, *new2; /* for holding alias name */ struct command *t = NULL; jmp_buf_t osetexit; int status; size_t omark; getexit(osetexit); if (seterr) { xfree(seterr); seterr = NULL; /* don't repeatedly print err msg. */ } w.word = STRNULL; new1 = xcalloc(1, sizeof w); new1->word = Strsave(s1); if (cnt == 1) { /* build a lex list with one word. */ w.next = w.prev = new1; new1->next = new1->prev = &w; } else { /* build a lex list with two words. */ new2 = xcalloc(1, sizeof w); new2->word = Strsave(s2); w.next = new2->prev = new1; new1->next = w.prev = new2; new1->prev = new2->next = &w; } cleanup_push(&w, lex_cleanup); /* Save the old status */ status = getn(varval(STRstatus)); /* expand aliases like process() does. */ alias(&w); /* build a syntax tree for the command. */ t = syntax(w.next, &w, 0); cleanup_push(t, syntax_cleanup); if (seterr) stderror(ERR_OLD); psavejob(); cleanup_push(&cnt, psavejob_cleanup); /* cnt is used only as a marker */ /* catch any errors here */ omark = cleanup_push_mark(); if (setexit() == 0) /* execute the parse tree. */ /* * From: Michael Schroeder <*****@*****.**> * was execute(t, tpgrp); */ execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL, TRUE); /* reset the error catcher to the old place */ cleanup_pop_mark(omark); resexit(osetexit); if (haderr) { haderr = 0; /* * Either precmd, or cwdcmd, or periodic had an error. Call it again so * that it is removed */ if (precmd_active) precmd(); if (postcmd_active) postcmd(); #ifdef notdef /* * XXX: On the other hand, just interrupting them causes an error too. * So if we hit ^C in the middle of cwdcmd or periodic the alias gets * removed. We don't want that. Note that we want to remove precmd * though, cause that could lead into an infinite loop. This should be * fixed correctly, but then haderr should give us the whole exit * status not just true or false. */ else if (cwdcmd_active) cwd_cmd(); else if (beepcmd_active) beep_cmd(); else if (periodic_active) period_cmd(); #endif /* notdef */ } cleanup_until(&w); pendjob(); /* Restore status */ setv(STRstatus, putn((tcsh_number_t)status), VAR_READWRITE); }
/* * Ndo maclisp do function. */ lispval Ndo() { register lispval current, where, handy; register struct nament *mybnp; register struct argent *lbot, *np; lispval atom, temp; lispval body, endtest, endform, varstuf, renewals[NDOVARS] ; struct argent *start, *last, *getem, *savedlbot; struct nament *savedbnp, *lastbnd; int count, index, saveme[SAVSIZE], virgin = 1; int myerrp; extern int errp; savedlbot = lbot; myerrp = errp; savedbnp = bnp; getexit(saveme); /* common nonlocal return */ if(retval = setexit()) { errp = myerrp; if(retval == BRRETN) { resexit(saveme); lbot = savedlbot; popnames(savedbnp); return((lispval) contval); } else { resexit(saveme); lbot = savedlbot; reset(retval); } } current = lbot->val; varstuf = current->car; switch( TYPE(varstuf) ) { case ATOM: /* This is old style maclisp do; atom is var, cadr(current) = init; caddr(current) = repeat etc. */ atom = varstuf; if(varstuf==nil) goto newstyle; bnp->atm = atom; /* save current binding of atom */ bnp++->val = atom->clb; if(bnp > bnplim) binderr(); current = current->cdr; atom->clb = eval(current->car); /* Init var. */ *renewals = (current = current->cdr)->car; /* get repeat form */ endtest = (current = current->cdr)->car; body = current->cdr; while(TRUE) { if(eval(endtest)!=nil) { resexit(saveme); popnames(savedbnp); return(nil); } doprog(body); atom->clb = eval(*renewals); } newstyle: case DTPR: /* New style maclisp do; atom is list of things of the form (var init repeat) */ count = 0; start = np; for(where = varstuf; where != nil; where = where->cdr) { /* do inits and count do vars. */ /* requires "simultaneous" eval of all inits */ handy = where->car->cdr; temp = nil; if(handy !=nil) temp = eval(handy->car); protect(temp); count++; } if(count > NDOVARS) error("More than 15 do vars",FALSE); bnp += count; if(bnp >= bnplim) { bnp = savedbnp; namerr(); } last = np; where = varstuf; mybnp = savedbnp; getem = start; for(index = 0; index < count; index++) { handy = where->car; /* get var name from group */ atom = handy->car; mybnp->atm = atom; mybnp->val = atom->clb; /* Swap current binding of atom for init val pushed on stack */ atom->clb = getem++->val; /* As long as we are down here in the list, save repeat form */ handy = handy->cdr->cdr; if(handy==nil) handy = CNIL; /* be sure not to rebind later */ else handy = handy->car; renewals[index] = handy; /* more loop "increments" */ where = where->cdr; mybnp++; } /* Examine End test and End form */ current = current->cdr; handy = current->car; body = current->cdr; if (handy == nil) { doprog(body); popnames(savedbnp); resexit(saveme); return(nil); } endtest = handy->car; endform = handy->cdr; /* The following is the loop: */ loop: if(eval(endtest)!=nil) { for(handy = nil; endform!=nil; endform = endform->cdr){ handy = eval(endform->car); } resexit(saveme); popnames(savedbnp); return(handy); } doprog(body); /* Simultaneously eval repeat forms */ for(index = 0; index < count; index++) { temp = renewals[index]; if (temp == nil || temp == CNIL) protect(temp); else protect(eval(temp)); } getem = (np = last); /* now simult. rebind all the atoms */ mybnp = savedbnp; for(index = 0; index < count; index++, getem++) { if( (getem)->val != CNIL ) /* if this atom has a repeat form */ mybnp->atm->clb = (getem)->val; /* rebind */ mybnp++; } goto loop; } }
static void srcunit(int unit, int onlyown, int hflg) { /* We have to push down a lot of state here */ /* All this could go into a structure */ struct whyle *oldwhyl; struct Bin saveB; sigset_t nsigset, osigset; jmp_buf oldexit; Char *oarginp, *oevalp, **oevalvec, *ogointr; Char OHIST; int oSHIN, oinsource, oldintty, oonelflg; int oenterhist, otell; /* The (few) real local variables */ int my_reenter; oSHIN = -1; oldintty = intty; oinsource = insource; oldwhyl = whyles; ogointr = gointr; oarginp = arginp; oevalp = evalp; oevalvec = evalvec; oonelflg = onelflg; oenterhist = enterhist; OHIST = HIST; otell = cantell; if (unit < 0) return; if (didfds) donefds(); if (onlyown) { struct stat stb; if (fstat(unit, &stb) < 0) { (void)close(unit); return; } } /* * There is a critical section here while we are pushing down the input * stream since we have stuff in different structures. If we weren't * careful an interrupt could corrupt SHIN's Bin structure and kill the * shell. * * We could avoid the critical region by grouping all the stuff in a single * structure and pointing at it to move it all at once. This is less * efficient globally on many variable references however. */ insource = 1; getexit(oldexit); if (setintr) { sigemptyset(&nsigset); (void)sigaddset(&nsigset, SIGINT); (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); } /* Setup the new values of the state stuff saved above */ (void)memcpy(&saveB, &B, sizeof(B)); fbuf = NULL; fseekp = feobp = fblocks = 0; oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0; intty = isatty(SHIN), whyles = 0, gointr = 0; evalvec = 0; evalp = 0; enterhist = hflg; if (enterhist) HIST = '\0'; /* * Now if we are allowing commands to be interrupted, we let ourselves be * interrupted. */ if (setintr) (void)sigprocmask(SIG_SETMASK, &osigset, NULL); settell(); if ((my_reenter = setexit()) == 0) process(0); /* 0 -> blow away on errors */ if (setintr) (void)sigprocmask(SIG_SETMASK, &osigset, NULL); if (oSHIN >= 0) { int i; /* We made it to the new state... free up its storage */ /* This code could get run twice but xfree doesn't care */ for (i = 0; i < fblocks; i++) xfree((ptr_t) fbuf[i]); xfree((ptr_t) fbuf); /* Reset input arena */ (void)memcpy(&B, &saveB, sizeof(B)); (void)close(SHIN), SHIN = oSHIN; arginp = oarginp, onelflg = oonelflg; evalp = oevalp, evalvec = oevalvec; intty = oldintty, whyles = oldwhyl, gointr = ogointr; if (enterhist) HIST = OHIST; enterhist = oenterhist; cantell = otell; } resexit(oldexit); /* * If process reset() (effectively an unwind) then we must also unwind. */ if (my_reenter) stderror(ERR_SILENT); insource = oinsource; }
static void backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal) { ssize_t icnt; Char c, *ip; struct command faket; int hadnl; int pvec[2], quoted; Char *fakecom[2], ibuf[BUFSIZE]; char tibuf[BUFSIZE]; hadnl = 0; icnt = 0; quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; faket.t_dtyp = NODE_COMMAND; faket.t_dflg = F_BACKQ; faket.t_dlef = 0; faket.t_drit = 0; faket.t_dspr = 0; faket.t_dcom = fakecom; fakecom[0] = STRfakecom1; fakecom[1] = 0; /* * We do the psave job to temporarily change the current job so that the * following fork is considered a separate job. This is so that when * backquotes are used in a builtin function that calls glob the "current * job" is not corrupted. We only need one level of pushed jobs as long as * we are sure to fork here. */ psavejob(); cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */ /* * It would be nicer if we could integrate this redirection more with the * routines in sh.sem.c by doing a fake execute on a builtin function that * was piped out. */ mypipe(pvec); cleanup_push(&pvec[0], open_cleanup); cleanup_push(&pvec[1], open_cleanup); if (pfork(&faket, -1) == 0) { jmp_buf_t osetexit; struct command *t; size_t omark; xclose(pvec[0]); (void) dmove(pvec[1], 1); (void) dmove(SHDIAG, 2); initdesc(); closem(); arginp = cp; for (arginp = cp; *cp; cp++) { *cp &= TRIM; if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r')) *cp = ' '; } /* * In the child ``forget'' everything about current aliases or * eval vectors. */ alvec = NULL; evalvec = NULL; alvecp = NULL; evalp = NULL; omark = cleanup_push_mark(); getexit(osetexit); for (;;) { (void) setexit(); justpr = 0; if (haderr) { /* unwind */ doneinp = 0; cleanup_pop_mark(omark); resexit(osetexit); reset(); } if (seterr) { xfree(seterr); seterr = NULL; } (void) lex(¶ml); cleanup_push(¶ml, lex_cleanup); if (seterr) stderror(ERR_OLD); alias(¶ml); t = syntax(paraml.next, ¶ml, 0); if (t == NULL) return; cleanup_push(t, syntax_cleanup); /* The F_BACKQ flag must set so the job output is correct if * printexitvalue is set. If it's not set, the job output * will have "Exit N" appended where N is the exit status. */ t->t_dflg = F_BACKQ|F_NOFORK; if (seterr) stderror(ERR_OLD); #ifdef SIGTSTP signal(SIGTSTP, SIG_IGN); #endif #ifdef SIGTTIN signal(SIGTTIN, SIG_IGN); #endif #ifdef SIGTTOU signal(SIGTTOU, SIG_IGN); #endif execute(t, -1, NULL, NULL, TRUE); cleanup_until(¶ml); } } cleanup_until(&pvec[1]); c = 0; ip = NULL; do { ssize_t cnt = 0; char *tmp; tmp = tibuf; for (;;) { while (icnt == 0) { int i, eof; ip = ibuf; icnt = xread(pvec[0], tmp, tibuf + BUFSIZE - tmp); eof = 0; if (icnt <= 0) { if (tmp == tibuf) goto eof; icnt = 0; eof = 1; } icnt += tmp - tibuf; i = 0; tmp = tibuf; while (tmp < tibuf + icnt) { int len; len = normal_mbtowc(&ip[i], tmp, tibuf + icnt - tmp); if (len == -1) { reset_mbtowc(); if (!eof && (size_t)(tibuf + icnt - tmp) < MB_CUR_MAX) { break; /* Maybe a partial character */ } ip[i] = (unsigned char) *tmp | INVALID_BYTE; /* Error */ } if (len <= 0) len = 1; i++; tmp += len; } if (tmp != tibuf) memmove (tibuf, tmp, tibuf + icnt - tmp); tmp = tibuf + (tibuf + icnt - tmp); icnt = i; } if (hadnl) break; --icnt; c = (*ip++ & TRIM); if (c == 0) break; #if defined(WINNT_NATIVE) || defined(__CYGWIN__) if (c == '\r') c = ' '; #endif /* WINNT_NATIVE || __CYGWIN__ */ if (c == '\n') { /* * Continue around the loop one more time, so that we can eat * the last newline without terminating this word. */ hadnl = 1; continue; } if (!quoted && (c == ' ' || c == '\t')) break; cnt++; Strbuf_append1(word, c | quoted); } /* * Unless at end-of-file, we will form a new word here if there were * characters in the word, or in any case when we take text literally. * If we didn't make empty words here when literal was set then we * would lose blank lines. */ if (c != 0 && (cnt || literal)) pword(bb, word); hadnl = 0; } while (c > 0); eof: cleanup_until(&pvec[0]); pwait(); cleanup_until(&faket); /* psavejob_cleanup(); */ }
/*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(); }
/* parseLS_COLORS(): * Parse the LS_COLORS environment variable */ void parseLS_COLORS(const Char *value) { size_t i, len; const Char *v; /* pointer in value */ char *c; /* pointer in colors */ Extension *volatile e; /* pointer in extensions */ jmp_buf_t osetexit; size_t omark; (void) &e; /* init */ xfree(extensions); for (i = 0; i < nvariables; i++) variables[i].color = variables[i].defaultcolor; colors = NULL; extensions = NULL; nextensions = 0; if (value == NULL) return; len = Strlen(value); /* allocate memory */ i = 1; for (v = value; *v; v++) if ((*v & CHAR) == ':') i++; extensions = xmalloc(len + i * sizeof(Extension)); colors = i * sizeof(Extension) + (char *)extensions; nextensions = 0; /* init pointers */ v = value; c = colors; e = &extensions[0]; /* Prevent from crashing if unknown parameters are given. */ omark = cleanup_push_mark(); getexit(osetexit); if (setexit() == 0) { /* parse */ while (*v) { switch (*v & CHAR) { case ':': v++; continue; case '*': /* :*ext=color: */ v++; if (getstring(&c, &v, &e->extension, '=') && 0 < e->extension.len) { v++; getstring(&c, &v, &e->color, ':'); e++; continue; } break; default: /* :vl=color: */ if (v[0] && v[1] && (v[2] & CHAR) == '=') { for (i = 0; i < nvariables; i++) if ((Char)variables[i].variable[0] == (v[0] & CHAR) && (Char)variables[i].variable[1] == (v[1] & CHAR)) break; if (i < nvariables) { v += 3; getstring(&c, &v, &variables[i].color, ':'); continue; } else stderror(ERR_BADCOLORVAR, v[0], v[1]); } break; } while (*v && (*v & CHAR) != ':') v++; } } cleanup_pop_mark(omark); resexit(osetexit); nextensions = e - extensions; }