diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1994-05-26 06:18:55 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1994-05-26 06:18:55 +0000 |
commit | e3cfc8ce61f788739c66445d903f8beacb40c93d (patch) | |
tree | ba7beef9ee9289c4383bad976f88710e44c98b4d /bin/csh/sem.c | |
parent | 862fdf11a2ede45dec0da01ed575525d79468981 (diff) | |
download | FreeBSD-src-e3cfc8ce61f788739c66445d903f8beacb40c93d.zip FreeBSD-src-e3cfc8ce61f788739c66445d903f8beacb40c93d.tar.gz |
BSD 4.4 Lite bin Sources
Diffstat (limited to 'bin/csh/sem.c')
-rw-r--r-- | bin/csh/sem.c | 645 |
1 files changed, 645 insertions, 0 deletions
diff --git a/bin/csh/sem.c b/bin/csh/sem.c new file mode 100644 index 0000000..584d3fb --- /dev/null +++ b/bin/csh/sem.c @@ -0,0 +1,645 @@ +/*- + * Copyright (c) 1980, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)sem.c 8.1 (Berkeley) 5/31/93"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#if __STDC__ +# include <stdarg.h> +#else +# include <varargs.h> +#endif + +#include "csh.h" +#include "proc.h" +#include "extern.h" + +static void vffree __P((int)); +static Char *splicepipe __P((struct command *t, Char *)); +static void doio __P((struct command *t, int *, int *)); +static void chkclob __P((char *)); + +void +execute(t, wanttty, pipein, pipeout) + register struct command *t; + int wanttty, *pipein, *pipeout; +{ + bool forked = 0; + struct biltins *bifunc; + int pid = 0; + int pv[2]; + + static sigset_t csigmask; + + static sigset_t ocsigmask; + static int onosigchld = 0; + static int nosigchld = 0; + + UNREGISTER(forked); + UNREGISTER(bifunc); + UNREGISTER(wanttty); + + if (t == 0) + return; + + if (t->t_dflg & F_AMPERSAND) + wanttty = 0; + switch (t->t_dtyp) { + + case NODE_COMMAND: + if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) + (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1); + if ((t->t_dflg & F_REPEAT) == 0) + Dfix(t); /* $ " ' \ */ + if (t->t_dcom[0] == 0) + return; + /* fall into... */ + + case NODE_PAREN: + if (t->t_dflg & F_PIPEOUT) + mypipe(pipeout); + /* + * 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) { + (void) close(0); + heredoc(t->t_dlef); + if (noexec) + (void) close(0); + } + + set(STRstatus, Strsave(STR0)); + + /* + * 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 = + 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], STRtime)) + if (t->t_dcom[1]) { + t->t_dflg |= F_TIME; + lshift(t->t_dcom, 1); + } + else + break; + 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->bfunct != dobreak && bifunc->bfunct != docontin && + bifunc->bfunct != doelse && bifunc->bfunct != doend && + bifunc->bfunct != doforeach && bifunc->bfunct != dogoto && + bifunc->bfunct != doif && bifunc->bfunct != dorepeat && + bifunc->bfunct != doswbrk && bifunc->bfunct != doswitch && + bifunc->bfunct != dowhile && bifunc->bfunct != dozip) + break; + } + } + else { /* not a command */ + bifunc = NULL; + if (noexec) + break; + } + + /* + * 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. + */ + /* + * Prevent forking cd, pushd, popd, chdir cause this will cause the + * shell not to change dir! + */ + if (bifunc && (bifunc->bfunct == dochngd || + bifunc->bfunct == dopushd || + bifunc->bfunct == 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)))) || + /* + * We have to fork for eval too. + */ + (bifunc && (t->t_dflg & (F_PIPEIN | F_PIPEOUT)) != 0 && + bifunc->bfunct == doeval)) + if (t->t_dtyp == NODE_PAREN || + t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) { + 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) { + csigmask = sigblock(sigmask(SIGCHLD)); + nosigchld = 1; + } + + pid = pfork(t, wanttty); + if (pid == 0 && nosigchld) { + (void) sigsetmask(csigmask); + nosigchld = 0; + } + else if (pid != 0 && (t->t_dflg & F_AMPERSAND)) + backpid = pid; + + } + else { + int ochild, osetintr, ohaderr, odidfds; + int oSHIN, oSHOUT, oSHERR, oOLDSTD, otpgrp; + sigset_t omask; + + /* + * 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. + */ + if (wanttty >= 0 && !nosigchld && !noexec) { + csigmask = sigblock(sigmask(SIGCHLD)); + nosigchld = 1; + } + omask = sigblock(sigmask(SIGCHLD) | sigmask(SIGINT)); + ochild = child; + osetintr = setintr; + ohaderr = haderr; + odidfds = didfds; + oSHIN = SHIN; + oSHOUT = SHOUT; + oSHERR = SHERR; + oOLDSTD = OLDSTD; + otpgrp = tpgrp; + ocsigmask = csigmask; + onosigchld = nosigchld; + Vsav = Vdp = 0; + Vexpath = 0; + Vt = 0; + pid = vfork(); + + if (pid < 0) { + (void) sigsetmask(omask); + stderror(ERR_NOPROC); + } + forked++; + if (pid) { /* parent */ + child = ochild; + setintr = osetintr; + haderr = ohaderr; + didfds = odidfds; + SHIN = oSHIN; + SHOUT = oSHOUT; + SHERR = oSHERR; + OLDSTD = oOLDSTD; + tpgrp = otpgrp; + csigmask = ocsigmask; + nosigchld = onosigchld; + + xfree((ptr_t) Vsav); + Vsav = 0; + xfree((ptr_t) Vdp); + Vdp = 0; + xfree((ptr_t) Vexpath); + Vexpath = 0; + blkfree((Char **) Vt); + Vt = 0; + /* this is from pfork() */ + palloc(pid, t); + (void) sigsetmask(omask); + } + else { /* child */ + /* this is from pfork() */ + int pgrp; + bool ignint = 0; + + if (nosigchld) { + (void) sigsetmask(csigmask); + 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; + if (ignint) { + (void) signal(SIGINT, SIG_IGN); + (void) signal(SIGQUIT, SIG_IGN); + } + else { + (void) signal(SIGINT, vffree); + (void) signal(SIGQUIT, SIG_DFL); + } + + if (wanttty >= 0) { + (void) signal(SIGTSTP, SIG_DFL); + (void) signal(SIGTTIN, SIG_DFL); + (void) signal(SIGTTOU, SIG_DFL); + } + + (void) signal(SIGTERM, parterm); + } + 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_NICE) + (void) setpriority(PRIO_PROCESS, 0, t->t_nice); + } + + } + 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. + */ + if (didfds == 0 && t->t_dflg & F_PIPEIN) { + (void) close(pipein[0]); + (void) close(pipein[1]); + } + if ((t->t_dflg & F_PIPEOUT) == 0) { + if (nosigchld) { + (void) sigsetmask(csigmask); + nosigchld = 0; + } + if ((t->t_dflg & F_AMPERSAND) == 0) + pwait(); + } + break; + } + doio(t, pipein, pipeout); + if (t->t_dflg & F_PIPEOUT) { + (void) close(pipeout[0]); + (void) close(pipeout[1]); + } + /* + * Perform a builtin function. If we are not forked, arrange for + * possible stopping + */ + if (bifunc) { + func(t, bifunc); + if (forked) + exitstat(); + break; + } + if (t->t_dtyp != NODE_PAREN) { + doexec(NULL, t); + /* NOTREACHED */ + } + /* + * For () commands must put new 0,1,2 in FSH* and recurse + */ + OLDSTD = dcopy(0, FOLDSTD); + SHOUT = dcopy(1, FSHOUT); + SHERR = dcopy(2, FSHERR); + (void) close(SHIN); + SHIN = -1; + didfds = 0; + wanttty = -1; + t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT; + execute(t->t_dspr, wanttty, NULL, NULL); + exitstat(); + + case NODE_PIPE: + t->t_dcar->t_dflg |= F_PIPEOUT | + (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT)); + execute(t->t_dcar, wanttty, pipein, pv); + t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & + (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT)); + if (wanttty > 0) + wanttty = 0; /* got tty already */ + execute(t->t_dcdr, wanttty, pv, pipeout); + break; + + case NODE_LIST: + if (t->t_dcar) { + t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; + execute(t->t_dcar, wanttty, NULL, NULL); + /* + * 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); + execute(t->t_dcdr, wanttty, NULL, NULL); + } + break; + + case NODE_OR: + case NODE_AND: + if (t->t_dcar) { + t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; + execute(t->t_dcar, wanttty, NULL, NULL); + if ((getn(value(STRstatus)) == 0) != + (t->t_dtyp == NODE_AND)) + return; + } + if (t->t_dcdr) { + t->t_dcdr->t_dflg |= t->t_dflg & + (F_NOFORK | F_NOINTERRUPT); + execute(t->t_dcdr, wanttty, NULL, NULL); + } + 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(); +} + +static void +vffree(i) +int i; +{ + register Char **v; + + if ((v = gargv) != NULL) { + gargv = 0; + xfree((ptr_t) v); + } + if ((v = pargv) != NULL) { + pargv = 0; + xfree((ptr_t) v); + } + _exit(i); +} + +/* + * 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(t, cp) + register 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); + } + 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]); +} + +/* + * Perform io redirection. + * We may or maynot be forked here. + */ +static void +doio(t, pipein, pipeout) + register struct command *t; + int *pipein, *pipeout; +{ + register int fd; + register Char *cp; + register int flags = t->t_dflg; + + if (didfds || (flags & F_REPEAT)) + return; + if ((flags & F_READ) == 0) {/* F_READ already done */ + if (t->t_dlef) { + char tmp[MAXPATHLEN+1]; + + /* + * so < /dev/std{in,out,err} work + */ + (void) dcopy(SHIN, 0); + (void) dcopy(SHOUT, 1); + (void) dcopy(SHERR, 2); + cp = splicepipe(t, t->t_dlef); + (void) strncpy(tmp, short2str(cp), MAXPATHLEN); + tmp[MAXPATHLEN] = '\0'; + xfree((ptr_t) cp); + if ((fd = open(tmp, O_RDONLY)) < 0) + stderror(ERR_SYSTEM, tmp, strerror(errno)); + (void) dmove(fd, 0); + } + else if (flags & F_PIPEIN) { + (void) close(0); + (void) dup(pipein[0]); + (void) close(pipein[0]); + (void) close(pipein[1]); + } + else if ((flags & F_NOINTERRUPT) && tpgrp == -1) { + (void) close(0); + (void) open(_PATH_DEVNULL, O_RDONLY); + } + else { + (void) close(0); + (void) dup(OLDSTD); + (void) ioctl(0, FIONCLEX, NULL); + } + } + if (t->t_drit) { + char tmp[MAXPATHLEN+1]; + + cp = splicepipe(t, t->t_drit); + (void) strncpy(tmp, short2str(cp), MAXPATHLEN); + tmp[MAXPATHLEN] = '\0'; + xfree((ptr_t) cp); + /* + * so > /dev/std{out,err} work + */ + (void) dcopy(SHOUT, 1); + (void) dcopy(SHERR, 2); + if ((flags & F_APPEND) && +#ifdef O_APPEND + (fd = open(tmp, O_WRONLY | O_APPEND)) >= 0); +#else + (fd = open(tmp, O_WRONLY)) >= 0) + (void) lseek(1, (off_t) 0, L_XTND); +#endif + else { + if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) { + if (flags & F_APPEND) + stderror(ERR_SYSTEM, tmp, strerror(errno)); + chkclob(tmp); + } + if ((fd = creat(tmp, 0666)) < 0) + stderror(ERR_SYSTEM, tmp, strerror(errno)); + } + (void) dmove(fd, 1); + } + else if (flags & F_PIPEOUT) { + (void) close(1); + (void) dup(pipeout[1]); + } + else { + (void) close(1); + (void) dup(SHOUT); + (void) ioctl(1, FIONCLEX, NULL); + } + + (void) close(2); + if (flags & F_STDERR) { + (void) dup(1); + } + else { + (void) dup(SHERR); + (void) ioctl(2, FIONCLEX, NULL); + } + didfds = 1; +} + +void +mypipe(pv) + register int *pv; +{ + + if (pipe(pv) < 0) + goto oops; + pv[0] = dmove(pv[0], -1); + pv[1] = dmove(pv[1], -1); + if (pv[0] >= 0 && pv[1] >= 0) + return; +oops: + stderror(ERR_PIPE); +} + +static void +chkclob(cp) + register char *cp; +{ + struct stat stb; + + if (stat(cp, &stb) < 0) + return; + if (S_ISCHR(stb.st_mode)) + return; + stderror(ERR_EXISTS, cp); +} |