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