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