xref: /original-bsd/bin/csh/sem.c (revision ba762ddc)
1 /*-
2  * Copyright (c) 1980, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)sem.c	5.11 (Berkeley) 04/04/91";
10 #endif /* not lint */
11 
12 #include "sh.h"
13 #include "sh.proc.h"
14 #include <sys/file.h>
15 #include <sys/ioctl.h>
16 #include "pathnames.h"
17 
18 /*
19  * C shell
20  */
21 
22 static int nosigchld = 0, osigmask;
23 static int onosigchld = 0, oosigmask;
24 /*VARARGS 1*/
25 execute(t, wanttty, pipein, pipeout)
26 	register struct command *t;
27 	int wanttty, *pipein, *pipeout;
28 {
29 	bool forked = 0;
30 	struct biltins *bifunc;
31 	int pid = 0;
32 	int pv[2];
33 
34 	if (t == 0)
35 		return;
36 	if ((t->t_dflg & F_AMPERSAND) && wanttty > 0)
37 		wanttty = 0;
38 	switch (t->t_dtyp) {
39 
40 	case NODE_COMMAND:
41 		if ((t->t_dcom[0][0] & (QUOTE|TRIM)) == QUOTE)
42 			(void) strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
43 		if ((t->t_dflg & F_REPEAT) == 0)
44 			Dfix(t);		/* $ " ' \ */
45 		if (t->t_dcom[0] == 0)
46 			return;
47 		/* fall into... */
48 
49 	case NODE_PAREN:
50 		if (t->t_dflg & F_PIPEOUT)
51 			mypipe(pipeout);
52 		/*
53 		 * Must do << early so parent will know
54 		 * where input pointer should be.
55 		 * If noexec then this is all we do.
56 		 */
57 		if (t->t_dflg & F_READ) {
58 			(void) close(0);
59 			heredoc(t->t_dlef);
60 			if (noexec)
61 				(void) close(0);
62 		}
63 		if (noexec)
64 			break;
65 
66 		set("status", "0");
67 
68 		/*
69 		 * This mess is the necessary kludge to handle the prefix
70 		 * builtins: nice, nohup, time.  These commands can also
71 		 * be used by themselves, and this is not handled here.
72 		 * This will also work when loops are parsed.
73 		 */
74 		while (t->t_dtyp == NODE_COMMAND)
75 			if (eq(t->t_dcom[0], "nice"))
76 				if (t->t_dcom[1])
77 					if (index("+-", t->t_dcom[1][0]))
78 						if (t->t_dcom[2]) {
79 							setname("nice");
80 							t->t_nice = getn(t->t_dcom[1]);
81 							lshift(t->t_dcom, 2);
82 							t->t_dflg |= F_NICE;
83 						} else
84 							break;
85 					else {
86 						t->t_nice = 4;
87 						lshift(t->t_dcom, 1);
88 						t->t_dflg |= F_NICE;
89 					}
90 				else
91 					break;
92 			else if (eq(t->t_dcom[0], "nohup"))
93 				if (t->t_dcom[1]) {
94 					t->t_dflg |= F_NOHUP;
95 					lshift(t->t_dcom, 1);
96 				} else
97 					break;
98 			else if (eq(t->t_dcom[0], "time"))
99 				if (t->t_dcom[1]) {
100 					t->t_dflg |= F_TIME;
101 					lshift(t->t_dcom, 1);
102 				} else
103 					break;
104 			else
105 				break;
106 		/*
107 		 * Check if we have a builtin function and remember which one.
108 		 */
109 		bifunc = t->t_dtyp ==
110 		    NODE_COMMAND ? isbfunc(t) : (struct biltins *) 0;
111 
112 		/*
113 		 * We fork only if we are timed, or are not the end of
114 		 * a parenthesized list and not a simple builtin function.
115 		 * Simple meaning one that is not pipedout, niced, nohupped,
116 		 * or &'d.
117 		 * It would be nice(?) to not fork in some of these cases.
118 		 */
119 		if (((t->t_dflg & F_TIME) || (t->t_dflg & F_NOFORK) == 0 &&
120 		    (!bifunc ||
121 		    t->t_dflg & (F_PIPEOUT|F_AMPERSAND|F_NICE|F_NOHUP))))
122 #ifdef VFORK
123 		    if (t->t_dtyp == NODE_PAREN ||
124 			t->t_dflg&(F_REPEAT|F_AMPERSAND) || bifunc)
125 #endif
126 			{ forked++;
127 			  if (wanttty >= 0 && !nosigchld) {
128 				osigmask = sigblock(sigmask(SIGCHLD));
129 				nosigchld = 1;
130 			  }
131 
132 			  pid = pfork(t, wanttty);
133 			  if (pid == 0 && nosigchld) {
134 				sigsetmask(osigmask);
135 				nosigchld = 0;
136 			  }
137 			}
138 #ifdef VFORK
139 		    else {
140 			sig_t vffree;
141 			int ochild, osetintr, ohaderr, odidfds;
142 			int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp;
143 			long omask;
144 
145 			/*
146 			 * Prepare for the vfork by saving everything
147 			 * that the child corrupts before it exec's.
148 			 * Note that in some signal implementations
149 			 * which keep the signal info in user space
150 			 * (e.g. Sun's) it will also be necessary to
151  			 * save and restore the current sigvec's for
152 			 * the signals the child touches before it
153 			 * exec's.
154 			 */
155 			if (wanttty >= 0 && !nosigchld && !noexec) {
156 				osigmask = sigblock(sigmask(SIGCHLD));
157 				nosigchld = 1;
158 			}
159 			omask = sigblock(sigmask(SIGCHLD));
160 			ochild = child; osetintr = setintr;
161 			ohaderr = haderr; odidfds = didfds;
162 			oSHIN = SHIN; oSHOUT = SHOUT;
163 			oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp;
164 			oosigmask = osigmask; onosigchld = nosigchld;
165 			Vsav = Vdp = 0; Vav = 0;
166 			pid = vfork();
167 			if (pid < 0) {
168 				(void) sigsetmask(omask);
169 				error("No more processes");
170 			}
171 			forked++;
172 			if (pid) {	/* parent */
173 				child = ochild; setintr = osetintr;
174 				haderr = ohaderr; didfds = odidfds;
175 				SHIN = oSHIN;
176 				SHOUT = oSHOUT; SHDIAG = oSHDIAG;
177 				OLDSTD = oOLDSTD; tpgrp = otpgrp;
178 				osigmask = oosigmask; nosigchld = onosigchld;
179 				xfree(Vsav); Vsav = 0;
180 				xfree(Vdp); Vdp = 0;
181 				xfree((char *)Vav); Vav = 0;
182 				/* this is from pfork() */
183 				palloc(pid, t);
184 				(void) sigsetmask(omask);
185 			} else {	/* child */
186 				/* this is from pfork() */
187 				int pgrp;
188 				bool ignint = 0;
189 
190 				if (nosigchld) {
191 					sigsetmask(osigmask);
192 					nosigchld = 0;
193 				}
194 				if (setintr)
195 					ignint = (tpgrp == -1 &&
196 					    (t->t_dflg&F_NOINTERRUPT)) ||
197 					    gointr && eq(gointr, "-");
198 				pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
199 				child++;
200 				if (setintr) {
201 					setintr = 0;
202 #ifdef notdef
203 					(void) signal(SIGCHLD, SIG_DFL);
204 #endif
205 					(void) signal(SIGINT, ignint ?
206 						SIG_IGN : vffree);
207 					(void) signal(SIGQUIT, ignint ?
208 						SIG_IGN : SIG_DFL);
209 					if (wanttty >= 0) {
210 						(void) signal(SIGTSTP, SIG_DFL);
211 						(void) signal(SIGTTIN, SIG_DFL);
212 						(void) signal(SIGTTOU, SIG_DFL);
213 					}
214 					(void) signal(SIGTERM, parterm);
215 				} else if (tpgrp == -1 &&
216 				    (t->t_dflg&F_NOINTERRUPT)) {
217 					(void) signal(SIGINT, SIG_IGN);
218 					(void) signal(SIGQUIT, SIG_IGN);
219 				}
220 				if (wanttty >= 0 && tpgrp >= 0)
221 					(void) setpgrp(0, pgrp);
222 				if (wanttty > 0)
223 					(void) ioctl(FSHTTY, TIOCSPGRP,
224 						(char *)&pgrp);
225 				if (tpgrp > 0)
226 					tpgrp = 0;
227 				if (t->t_dflg & F_NOHUP)
228 					(void) signal(SIGHUP, SIG_IGN);
229 				if (t->t_dflg & F_NICE)
230 					(void) setpriority(PRIO_PROCESS,
231 						0, t->t_nice);
232 			}
233 
234 		    }
235 #endif
236 		if (pid != 0) {
237 			/*
238 			 * It would be better if we could wait for the
239 			 * whole job when we knew the last process
240 			 * had been started.  Pwait, in fact, does
241 			 * wait for the whole job anyway, but this test
242 			 * doesn't really express our intentions.
243 			 */
244 			if (didfds==0 && t->t_dflg&F_PIPEIN) {
245 				(void) close(pipein[0]);
246 				(void) close(pipein[1]);
247 			}
248 			if ((t->t_dflg & F_PIPEOUT) == 0) {
249 				if (nosigchld) {
250 #ifdef foobarbaz
251 					printf("DID\n");
252 #endif
253 					sigsetmask(osigmask);
254 					nosigchld = 0;
255 				}
256 				if ((t->t_dflg & F_AMPERSAND) == 0)
257 					pwait();
258 			}
259 			break;
260 		}
261 		doio(t, pipein, pipeout);
262 		if (t->t_dflg & F_PIPEOUT) {
263 			(void) close(pipeout[0]);
264 			(void) close(pipeout[1]);
265 		}
266 
267 		/*
268 		 * Perform a builtin function.
269 		 * If we are not forked, arrange for possible stopping
270 		 */
271 		if (bifunc) {
272 			func(t, bifunc);
273 			if (forked)
274 				exitstat();
275 			break;
276 		}
277 		if (t->t_dtyp != NODE_PAREN) {
278 			doexec(t);
279 			/*NOTREACHED*/
280 		}
281 		/*
282 		 * For () commands must put new 0,1,2 in FSH* and recurse
283 		 */
284 		OLDSTD = dcopy(0, FOLDSTD);
285 		SHOUT = dcopy(1, FSHOUT);
286 		SHDIAG = dcopy(2, FSHDIAG);
287 		(void) close(SHIN);
288 		SHIN = -1;
289 		didfds = 0;
290 		wanttty = -1;
291 		t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT;
292 		execute(t->t_dspr, wanttty);
293 		exitstat();
294 
295 	case NODE_PIPE:
296 		t->t_dcar->t_dflg |= F_PIPEOUT |
297 		    (t->t_dflg & (F_PIPEIN|F_AMPERSAND|F_STDERR|F_NOINTERRUPT));
298 		execute(t->t_dcar, wanttty, pipein, pv);
299 		t->t_dcdr->t_dflg |= F_PIPEIN |
300 		    (t->t_dflg &
301 		    (F_PIPEOUT|F_AMPERSAND|F_NOFORK|F_NOINTERRUPT));
302 		if (wanttty > 0)
303 			wanttty = 0;		/* got tty already */
304 		execute(t->t_dcdr, wanttty, pv, pipeout);
305 		break;
306 
307 	case NODE_LIST:
308 		if (t->t_dcar) {
309 			t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
310 			execute(t->t_dcar, wanttty);
311 			/*
312 			 * In strange case of A&B make a new job after A
313 			 */
314 			if (t->t_dcar->t_dflg&F_AMPERSAND && t->t_dcdr &&
315 			    (t->t_dcdr->t_dflg&F_AMPERSAND) == 0)
316 				pendjob();
317 		}
318 		if (t->t_dcdr) {
319 			t->t_dcdr->t_dflg |=
320 			    t->t_dflg & (F_NOFORK|F_NOINTERRUPT);
321 			execute(t->t_dcdr, wanttty);
322 		}
323 		break;
324 
325 	case NODE_OR:
326 	case NODE_AND:
327 		if (t->t_dcar) {
328 			t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
329 			execute(t->t_dcar, wanttty);
330 			if ((getn(value("status")) == 0) !=
331 			    (t->t_dtyp == NODE_AND))
332 				return;
333 		}
334 		if (t->t_dcdr) {
335 			t->t_dcdr->t_dflg |=
336 			    t->t_dflg & (F_NOFORK|F_NOINTERRUPT);
337 			execute(t->t_dcdr, wanttty);
338 		}
339 		break;
340 	}
341 	/*
342 	 * Fall through for all breaks from switch.
343 	 *
344 	 * If there will be no more executions of this command, flush all
345 	 * file descriptors.  Places that turn on the F_REPEAT bit are
346 	 * responsible for doing donefds after the last re-execution
347 	 */
348 	if (didfds && !(t->t_dflg & F_REPEAT))
349 		donefds();
350 }
351 
352 #ifdef VFORK
353 vffree()
354 {
355 	register char **v;
356 
357 	if (v = gargv)
358 		gargv = 0, xfree((char *)v);
359 	if (v = pargv)
360 		pargv = 0, xfree((char *)v);
361 	_exit(1);
362 }
363 #endif
364 
365 /*
366  * Perform io redirection.
367  * We may or maynot be forked here.
368  */
369 doio(t, pipein, pipeout)
370 	register struct command *t;
371 	int *pipein, *pipeout;
372 {
373 	register char *cp;
374 	register int flags = t->t_dflg;
375 
376 	if (didfds || (flags & F_REPEAT))
377 		return;
378 	if ((flags & F_READ) == 0) {	/* F_READ already done */
379 		(void) close(0);
380 		if (cp = t->t_dlef) {
381 			cp = globone(Dfix1(cp));
382 			xfree(cp);
383 			if (open(cp, 0) < 0)
384 				Perror(cp);
385 		} else if (flags & F_PIPEIN) {
386 			(void) dup(pipein[0]);
387 			(void) close(pipein[0]);
388 			(void) close(pipein[1]);
389 		} else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
390 			(void) close(0);
391 			(void) open(_PATH_DEVNULL, 0);
392 		} else
393 			(void) dup(OLDSTD);
394 	}
395 	(void) close(1);
396 	if (cp = t->t_drit) {
397 		cp = globone(Dfix1(cp));
398 		xfree(cp);
399 		if (!(flags & F_APPEND) || open(cp, O_WRONLY|O_APPEND, 0) < 0) {
400 			if (!(flags & F_OVERWRITE) && adrof("noclobber")) {
401 				if (flags & F_APPEND)
402 					Perror(cp);
403 				chkclob(cp);
404 			}
405 			if (creat(cp, 0666) < 0)
406 				Perror(cp);
407 		}
408 	} else if (flags & F_PIPEOUT)
409 		(void) dup(pipeout[1]);
410 	else
411 		(void) dup(SHOUT);
412 
413 	(void) close(2);
414 	if (flags & F_STDERR)
415 		(void) dup(1);
416 	else
417 		(void) dup(SHDIAG);
418 	didfds = 1;
419 }
420 
421 mypipe(pv)
422 	register int *pv;
423 {
424 
425 	if (pipe(pv) < 0)
426 		goto oops;
427 	pv[0] = dmove(pv[0], -1);
428 	pv[1] = dmove(pv[1], -1);
429 	if (pv[0] >= 0 && pv[1] >= 0)
430 		return;
431 oops:
432 	error("Can't make pipe");
433 }
434 
435 chkclob(cp)
436 	register char *cp;
437 {
438 	struct stat stb;
439 
440 	if (stat(cp, &stb) < 0)
441 		return;
442 	if ((stb.st_mode & S_IFMT) == S_IFCHR)
443 		return;
444 	error("%s: File exists", cp);
445 }
446