Home | History | Annotate | Download | only in csh
      1 /*
      2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
      7 /*	  All Rights Reserved  	*/
      8 
      9 /*
     10  * Copyright (c) 1980 Regents of the University of California.
     11  * All rights reserved. The Berkeley Software License Agreement
     12  * specifies the terms and conditions for redistribution.
     13  */
     14 
     15 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     16 
     17 #include <unistd.h>
     18 #include <fcntl.h>
     19 #include "sh.h"
     20 #include "sh.proc.h"
     21 #include "sh.tconst.h"
     22 
     23 /*
     24  * C shell
     25  */
     26 
     27 void	doio(struct command *, int *, int *);
     28 void	mypipe(int *);
     29 void	chkclob(tchar *);
     30 
     31 /*
     32  * Return true if there is a back-quote (`) anywhere in the argument list.
     33  * Its presence would cause glob() to be invoked in the child process
     34  * and this would cause chaos if the child is created with vfork().
     35  */
     36 static bool
     37 AnyBquote(struct command *t)
     38 {
     39 	tchar **pp;
     40 	tchar *p;
     41 
     42 	if (noexec)
     43 		return (0);
     44 	for (pp = t->t_dcom; p = *pp++;) {
     45 		if (any('`', p))
     46 			return (1);
     47 	}
     48 	return (0);
     49 }
     50 
     51 /*VARARGS 1*/
     52 void
     53 execute(t, wanttty, pipein, pipeout)
     54 	struct command *t;
     55 	int wanttty, *pipein, *pipeout;
     56 {
     57 	bool forked = 0;
     58 	struct biltins *bifunc;
     59 	int pid = 0;
     60 	int pv[2];
     61 	extern int globcnt;
     62 #ifdef TRACE
     63 	tprintf("TRACE- execute()\n");
     64 #endif
     65 
     66 	if (t == 0)
     67 		return;
     68 	if ((t->t_dflg & FAND) && wanttty > 0)
     69 		wanttty = 0;
     70 	switch (t->t_dtyp) {
     71 
     72 	case TCOM:
     73 		if (t->t_dcom[0][0] == (tchar)S_TOPBIT[0])
     74 			(void) strcpy_(t->t_dcom[0], t->t_dcom[0] + 1);
     75 		if ((t->t_dflg & FREDO) == 0)
     76 			Dfix(t);		/* $ " ' \ */
     77 		if (t->t_dcom[0] == 0)
     78 			return;
     79 		/* fall into... */
     80 
     81 	case TPAR:
     82 		if (t->t_dflg & FPOU)
     83 			mypipe(pipeout);
     84 		/*
     85 		 * Must do << early so parent will know
     86 		 * where input pointer should be.
     87 		 * If noexec then this is all we do.
     88 		 */
     89 		if (t->t_dflg & FHERE) {
     90 			(void) close(0);
     91 			unsetfd(0);
     92 			heredoc(t->t_dlef);
     93 			if (noexec) {
     94 				(void) close(0);
     95 				unsetfd(0);
     96 			}
     97 		}
     98 		if (noexec)
     99 			break;
    100 
    101 		set(S_status, S_0);
    102 
    103 		/*
    104 		 * This mess is the necessary kludge to handle the prefix
    105 		 * builtins: nice, nohup, time.  These commands can also
    106 		 * be used by themselves, and this is not handled here.
    107 		 * This will also work when loops are parsed.
    108 		 */
    109 		while (t->t_dtyp == TCOM)
    110 			if (eq(t->t_dcom[0], S_nice /*"nice"*/))
    111 				if (t->t_dcom[1])
    112 					/*if (any(t->t_dcom[1][0], "+-"))*/
    113 					if (t->t_dcom[1][0] == '+' ||
    114 					    t->t_dcom[1][0] == '-')
    115 						if (t->t_dcom[2]) {
    116 							setname(S_nice /*"nice"*/);
    117 							t->t_nice = getn(t->t_dcom[1]);
    118 							lshift(t->t_dcom, 2);
    119 							t->t_dflg |= FNICE;
    120 						} else
    121 							break;
    122 					else {
    123 						t->t_nice = 4;
    124 						lshift(t->t_dcom, 1);
    125 						t->t_dflg |= FNICE;
    126 					}
    127 				else
    128 					break;
    129 			else if (eq(t->t_dcom[0], S_nohup /*"nohup"*/))
    130 				if (t->t_dcom[1]) {
    131 					t->t_dflg |= FNOHUP;
    132 					lshift(t->t_dcom, 1);
    133 				} else
    134 					break;
    135 			else if (eq(t->t_dcom[0], S_time /*"time"*/))
    136 				if (t->t_dcom[1]) {
    137 					t->t_dflg |= FTIME;
    138 					lshift(t->t_dcom, 1);
    139 				} else
    140 					break;
    141 			else
    142 				break;
    143 		/*
    144 		 * Check if we have a builtin function and remember which one.
    145 		 */
    146 		bifunc = t->t_dtyp == TCOM ? isbfunc(t) : (struct biltins *) 0;
    147 
    148 		/*
    149 		 * We fork only if we are timed, or are not the end of
    150 		 * a parenthesized list and not a simple builtin function.
    151 		 * Simple meaning one that is not pipedout, niced, nohupped,
    152 		 * or &'d.
    153 		 * It would be nice(?) to not fork in some of these cases.
    154 		 */
    155 		if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 &&
    156 		     (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP))))
    157 #ifdef VFORK
    158 		    if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) ||
    159 			bifunc || AnyBquote(t))
    160 #endif
    161 			{ forked++; pid = pfork(t, wanttty); }
    162 #ifdef VFORK
    163 		    else {
    164 			void vffree();
    165 			struct sv {
    166 				int mask, child, setintr, haderr, didfds;
    167 				int SHIN, SHOUT, SHDIAG, OLDSTD, tpgrp;
    168 				struct sigvec sigv;
    169 			} sv;
    170 
    171 			/*
    172 			 * Prepare for the vfork by saving everything
    173 			 * that the child corrupts before it exec's.
    174 			 * Note that in some signal implementations
    175 			 * which keep the signal info in user space
    176 			 * (e.g. Sun's) it will also be necessary to
    177  			 * save and restore the current sigvec's for
    178 			 * the signals the child touches before it
    179 			 * exec's.
    180 			 */
    181 			sv.mask = sigblock(sigmask(SIGCHLD));
    182 			sv.child = child; sv.setintr = setintr;
    183 			sv.haderr = haderr; sv.didfds = didfds;
    184 			sv.SHIN = SHIN; sv.SHOUT = SHOUT;
    185 			sv.SHDIAG = SHDIAG; sv.OLDSTD = OLDSTD;
    186 			sv.tpgrp = tpgrp;
    187 			Vsav = Vdp = 0; Vav = 0;
    188 			(void) sigvec(SIGINT, (struct sigvec *)0, &sv.sigv);
    189 			pid = vfork();
    190 			if (pid < 0) {
    191 				(void) sigsetmask(sv.mask);
    192 				error("Vfork failed");
    193 			}
    194 			forked++;
    195 			if (pid) {	/* parent */
    196 				int ppid;
    197 				closelog();
    198 				child = sv.child; setintr = sv.setintr;
    199 				haderr = sv.haderr; didfds = sv.didfds;
    200 				SHIN = sv.SHIN;
    201 				SHOUT = sv.SHOUT; SHDIAG = sv.SHDIAG;
    202 				OLDSTD = sv.OLDSTD; tpgrp = sv.tpgrp;
    203 				xfree(Vsav); Vsav = 0;
    204 				xfree(Vdp); Vdp = 0;
    205 				xfree( (tchar *)Vav); Vav = 0;
    206 				/* this is from pfork() */
    207 				ppid = pcurrjob ? pcurrjob->p_jobid : pid;
    208 				if (wanttty >= 0 && tpgrp >= 0)
    209 					setpgid (ppid, ppid);
    210 				palloc(pid, t);
    211 				/*
    212 				 * Restore SIGINT handler.
    213 				 */
    214 				(void) sigvec(SIGINT, &sv.sigv, (struct sigvec *)0);
    215 				(void) sigsetmask(sv.mask);
    216 			} else {	/* child */
    217 				/* this is from pfork() */
    218 				int pgrp;
    219 				bool ignint = 0;
    220 				int sigttou;
    221 				if (setintr)
    222 					ignint =
    223 					    (tpgrp == -1 && (t->t_dflg&FINT))
    224 					    || gointr
    225 						&& eq(gointr, S_MINUS/*"-"*/);
    226 				pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
    227 				child++;
    228 				if (setintr) {
    229 					setintr = 0;
    230 #ifdef notdef
    231 					(void) signal(SIGCHLD, SIG_DFL);
    232 #endif
    233 					(void) signal(SIGINT, ignint ?
    234 						SIG_IGN : vffree);
    235 					(void) signal(SIGQUIT, ignint ?
    236 						SIG_IGN : SIG_DFL);
    237 					if (wanttty >= 0) {
    238 						(void) signal(SIGTSTP, SIG_DFL);
    239 						(void) signal(SIGTTIN, SIG_DFL);
    240 						(void) signal(SIGTTOU, SIG_DFL);
    241 					}
    242 					(void) signal(SIGTERM, parterm);
    243 				} else if (tpgrp == -1 && (t->t_dflg&FINT)) {
    244 					(void) signal(SIGINT, SIG_IGN);
    245 					(void) signal(SIGQUIT, SIG_IGN);
    246 				}
    247 				if (wanttty >= 0 && tpgrp >= 0)
    248 					(void) setpgid(0, pgrp);
    249 				if (wanttty > 0) {
    250 					sigttou = sigblock (
    251 						sigmask(SIGTTOU) |
    252 						sigmask(SIGTTIN) |
    253 						sigmask(SIGTSTP));
    254 					(void) ioctl(FSHTTY, TIOCSPGRP,
    255 						 (tchar *)&pgrp);
    256 					sigsetmask (sigttou);
    257 				}
    258 				if (tpgrp > 0)
    259 					tpgrp = 0;
    260 				if (t->t_dflg & FNOHUP)
    261 					(void) signal(SIGHUP, SIG_IGN);
    262 				if (t->t_dflg & FNICE)
    263 					(void) setpriority(PRIO_PROCESS,
    264 						0, t->t_nice);
    265 			}
    266 
    267 		    }
    268 #endif
    269 		if (pid != 0) {
    270 			/*
    271 			 * It would be better if we could wait for the
    272 			 * whole job when we knew the last process
    273 			 * had been started.  Pwait, in fact, does
    274 			 * wait for the whole job anyway, but this test
    275 			 * doesn't really express our intentions.
    276 			 */
    277 			if (didfds==0 && t->t_dflg&FPIN) {
    278 				(void) close(pipein[0]);
    279 				unsetfd(pipein[0]);
    280 				(void) close(pipein[1]);
    281 				unsetfd(pipein[1]);
    282 			}
    283 			if ((t->t_dflg & (FPOU|FAND)) == 0)
    284 				pwait();
    285 			break;
    286 		}
    287 		doio(t, pipein, pipeout);
    288 		if (t->t_dflg & FPOU) {
    289 			(void) close(pipeout[0]);
    290 			(void) unsetfd(pipeout[0]);
    291 			(void) close(pipeout[1]);
    292 			(void) unsetfd(pipeout[1]);
    293 		}
    294 
    295 		/*
    296 		 * Perform a builtin function.
    297 		 * If we are not forked, arrange for possible stopping
    298 		 */
    299 		if (bifunc) {
    300 			func(t, bifunc);
    301 			if (forked)
    302 				exitstat();
    303 			break;
    304 		}
    305 		if (t->t_dtyp != TPAR) {
    306 			doexec(t);
    307 			/*NOTREACHED*/
    308 		}
    309 		/*
    310 		 * For () commands must put new 0,1,2 in FSH* and recurse
    311 		 */
    312 		OLDSTD = dcopy(0, FOLDSTD);
    313 		SHOUT = dcopy(1, FSHOUT);
    314 		SHDIAG = dcopy(2, FSHDIAG);
    315 		(void) close(SHIN);
    316 		(void) unsetfd(SHIN);
    317 		SHIN = -1;
    318 		didfds = 0;
    319 		wanttty = -1;
    320 		t->t_dspr->t_dflg |= t->t_dflg & FINT;
    321 		execute(t->t_dspr, wanttty);
    322 		exitstat();
    323 
    324 	case TFIL:
    325 		t->t_dcar->t_dflg |= FPOU |
    326 		    (t->t_dflg & (FPIN|FAND|FDIAG|FINT));
    327 		execute(t->t_dcar, wanttty, pipein, pv);
    328 		t->t_dcdr->t_dflg |= FPIN |
    329 		    (t->t_dflg & (FPOU|FAND|FPAR|FINT));
    330 		if (wanttty > 0)
    331 			wanttty = 0;		/* got tty already */
    332 		execute(t->t_dcdr, wanttty, pv, pipeout);
    333 		break;
    334 
    335 	case TLST:
    336 		if (t->t_dcar) {
    337 			t->t_dcar->t_dflg |= t->t_dflg & FINT;
    338 			execute(t->t_dcar, wanttty);
    339 			/*
    340 			 * In strange case of A&B make a new job after A
    341 			 */
    342 			if (t->t_dcar->t_dflg&FAND && t->t_dcdr &&
    343 			    (t->t_dcdr->t_dflg&FAND) == 0)
    344 				pendjob();
    345 		}
    346 		if (t->t_dcdr) {
    347 			t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
    348 			execute(t->t_dcdr, wanttty);
    349 		}
    350 		break;
    351 
    352 	case TOR:
    353 	case TAND:
    354 		if (t->t_dcar) {
    355 			t->t_dcar->t_dflg |= t->t_dflg & FINT;
    356 			execute(t->t_dcar, wanttty);
    357 			if ((getn(value(S_status/*"status"*/)) == 0) != (t->t_dtyp == TAND))
    358 				return;
    359 		}
    360 		if (t->t_dcdr) {
    361 			t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
    362 			execute(t->t_dcdr, wanttty);
    363 		}
    364 		break;
    365 	}
    366 	/*
    367 	 * Fall through for all breaks from switch
    368 	 *
    369 	 * If there will be no more executions of this
    370 	 * command, flush all file descriptors.
    371 	 * Places that turn on the FREDO bit are responsible
    372 	 * for doing donefds after the last re-execution
    373 	 */
    374 	if (didfds && !(t->t_dflg & FREDO))
    375 		donefds();
    376 
    377 	/*
    378 	 * If glob() was called and arguments list is not yet
    379 	 * free'ed, free them here.
    380 	 */
    381 	if (gargv) {
    382 		blkfree(gargv);
    383 		gargv = 0;
    384 		globcnt = 0;
    385 	}
    386 }
    387 
    388 #ifdef VFORK
    389 void
    390 vffree(void)
    391 {
    392 	tchar **v;
    393 
    394 #ifdef TRACE
    395 	tprintf("TRACE- vffree()\n");
    396 #endif
    397 	if (v = gargv)
    398 		gargv = 0, xfree( (tchar *)v);
    399 	if (v = pargv)
    400 		pargv = 0, xfree( (tchar *)v);
    401 	_exit(1);
    402 }
    403 #endif
    404 
    405 /*
    406  * Perform io redirection.
    407  * We may or maynot be forked here.
    408  */
    409 void
    410 doio(struct command *t, int *pipein, int *pipeout)
    411 {
    412 	tchar *cp, *dp;
    413 	int flags = t->t_dflg;
    414 	int fd;
    415 
    416 #ifdef TRACE
    417 	tprintf("TRACE- doio()\n");
    418 #endif
    419 	if (didfds || (flags & FREDO))
    420 		return;
    421 	if ((flags & FHERE) == 0) {	/* FHERE already done */
    422 		(void) close(0);
    423 		(void) unsetfd(0);
    424 		if (cp = t->t_dlef) {
    425 			dp = Dfix1(cp);
    426 			cp = globone(dp);
    427 			xfree(dp);
    428 			xfree(cp);
    429 			if (open_(cp, 0) < 0)
    430 				Perror(cp);
    431 		} else if (flags & FPIN) {
    432 			fd = dup(pipein[0]);
    433 			if (fd != -1)
    434 				setfd(fd);
    435 			(void) close(pipein[0]);
    436 			(void) unsetfd(pipein[0]);
    437 			(void) close(pipein[1]);
    438 			(void) unsetfd(pipein[1]);
    439 		} else if ((flags & FINT) && tpgrp == -1) {
    440 			(void) close(0);	/* no need for unsetfd */
    441 			(void) open("/dev/null", 0); /* no need for setfd */
    442 		} else {
    443 			fd = dup(OLDSTD);
    444 			if (fd != -1)
    445 				setfd(fd);
    446 		}
    447 	}
    448 	(void) close(1);
    449 	(void) unsetfd(1);
    450 	if (cp = t->t_drit) {
    451 		dp = Dfix1(cp);
    452 		cp = globone(dp);
    453 		xfree(dp);
    454 		if ((flags & FCAT) && open_(cp, 1) >= 0)
    455 			(void) lseek(1, (off_t)0, 2);
    456 		else {
    457 			if (!(flags & FANY) && adrof(S_noclobber/*"noclobber"*/)) {
    458 				if (flags & FCAT)
    459 					Perror(cp);
    460 				chkclob(cp);
    461 			}
    462 			if (creat_(cp, 0666) < 0)
    463 				Perror(cp);
    464 		}
    465 		xfree(cp);
    466 	} else if (flags & FPOU) {
    467 		fd = dup(pipeout[1]);
    468 		if (fd != -1)
    469 			setfd (fd);
    470 	}
    471 	else {
    472 		fd = dup(SHOUT);
    473 		if (fd != -1)
    474 			setfd(fd);
    475 	}
    476 
    477 	(void) close(2);
    478 	(void) unsetfd(2);
    479 	if (flags & FDIAG) {
    480 		fd = dup(1);
    481 		if (fd != -1)
    482 			setfd(fd);
    483 	}
    484 	else {
    485 		fd = dup(SHDIAG);
    486 		if (fd != -1)
    487 			setfd(fd);
    488 	}
    489 	didfds = 1;
    490 }
    491 
    492 void
    493 mypipe(int *pv)
    494 {
    495 
    496 #ifdef TRACE
    497 	tprintf("TRACE- mypipe()\n");
    498 #endif
    499 	if (pipe(pv) < 0)
    500 		goto oops;
    501 	setfd(pv[0]);
    502 	setfd(pv[1]);
    503 
    504 	pv[0] = dmove(pv[0], -1);
    505 	pv[1] = dmove(pv[1], -1);
    506 	if (pv[0] >= 0 && pv[1] >= 0)
    507 		return;
    508 oops:
    509 	error("Can't make pipe");
    510 }
    511 
    512 void
    513 chkclob(tchar *cp)
    514 {
    515 	struct stat stb;
    516 	unsigned short	type;
    517 
    518 #ifdef TRACE
    519 	tprintf("TRACE- chkclob()\n");
    520 #endif
    521 	if (stat_(cp, &stb) < 0)
    522 		return;
    523 	type = stb.st_mode & S_IFMT;
    524 	if (type == S_IFCHR || type == S_IFIFO)
    525 		return;
    526 	error("%t: File exists", cp);
    527 }
    528