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