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
27void	doio(struct command *, int *, int *);
28void	mypipe(int *);
29void	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 */
36static bool
37AnyBquote(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*/
52void
53execute(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
389void
390vffree(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 */
409void
410doio(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
492void
493mypipe(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;
508oops:
509	error("Can't make pipe");
510}
511
512void
513chkclob(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