xref: /original-bsd/bin/csh/sem.c (revision becca096)
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.17 (Berkeley) 06/17/91";
10 #endif /* not lint */
11 
12 #include <sys/param.h>
13 #include <sys/ioctl.h>
14 #include <sys/stat.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #if __STDC__
21 # include <stdarg.h>
22 #else
23 # include <varargs.h>
24 #endif
25 
26 #include "csh.h"
27 #include "proc.h"
28 #include "extern.h"
29 
30 static void	vffree __P((int));
31 static void	doio __P((struct command *t, int *, int *));
32 static void	chkclob __P((char *));
33 
34 void
35 execute(t, wanttty, pipein, pipeout)
36     register struct command *t;
37     int     wanttty, *pipein, *pipeout;
38 {
39     bool    forked = 0;
40     struct biltins *bifunc;
41     int     pid = 0;
42     int     pv[2];
43 
44     static sigset_t csigmask;
45 
46     static sigset_t ocsigmask;
47     static int onosigchld = 0;
48     static int nosigchld = 0;
49 
50     if (t == 0)
51 	return;
52 
53     if (t->t_dflg & F_AMPERSAND)
54 	wanttty = 0;
55     switch (t->t_dtyp) {
56 
57     case NODE_COMMAND:
58 	if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
59 	    (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
60 	if ((t->t_dflg & F_REPEAT) == 0)
61 	    Dfix(t);		/* $ " ' \ */
62 	if (t->t_dcom[0] == 0)
63 	    return;
64 	/* fall into... */
65 
66     case NODE_PAREN:
67 	if (t->t_dflg & F_PIPEOUT)
68 	    mypipe(pipeout);
69 	/*
70 	 * Must do << early so parent will know where input pointer should be.
71 	 * If noexec then this is all we do.
72 	 */
73 	if (t->t_dflg & F_READ) {
74 	    (void) close(0);
75 	    heredoc(t->t_dlef);
76 	    if (noexec)
77 		(void) close(0);
78 	}
79 	if (noexec)
80 	    break;
81 
82 	set(STRstatus, Strsave(STR0));
83 
84 	/*
85 	 * This mess is the necessary kludge to handle the prefix builtins:
86 	 * nice, nohup, time.  These commands can also be used by themselves,
87 	 * and this is not handled here. This will also work when loops are
88 	 * parsed.
89 	 */
90 	while (t->t_dtyp == NODE_COMMAND)
91 	    if (eq(t->t_dcom[0], STRnice))
92 		if (t->t_dcom[1])
93 		    if (strchr("+-", t->t_dcom[1][0]))
94 			if (t->t_dcom[2]) {
95 			    setname("nice");
96 			    t->t_nice =
97 				getn(t->t_dcom[1]);
98 			    lshift(t->t_dcom, 2);
99 			    t->t_dflg |= F_NICE;
100 			}
101 			else
102 			    break;
103 		    else {
104 			t->t_nice = 4;
105 			lshift(t->t_dcom, 1);
106 			t->t_dflg |= F_NICE;
107 		    }
108 		else
109 		    break;
110 	    else if (eq(t->t_dcom[0], STRnohup))
111 		if (t->t_dcom[1]) {
112 		    t->t_dflg |= F_NOHUP;
113 		    lshift(t->t_dcom, 1);
114 		}
115 		else
116 		    break;
117 	    else if (eq(t->t_dcom[0], STRtime))
118 		if (t->t_dcom[1]) {
119 		    t->t_dflg |= F_TIME;
120 		    lshift(t->t_dcom, 1);
121 		}
122 		else
123 		    break;
124 	    else
125 		break;
126 
127 	/* is t a command */
128 	if (t->t_dtyp == NODE_COMMAND) {
129 	    /*
130 	     * Check if we have a builtin function and remember which one.
131 	     */
132 	    bifunc = isbfunc(t);
133 	}
134 	else {			/* not a command */
135 	    bifunc = NULL;
136 	}
137 
138 	/*
139 	 * We fork only if we are timed, or are not the end of a parenthesized
140 	 * list and not a simple builtin function. Simple meaning one that is
141 	 * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not
142 	 * fork in some of these cases.
143 	 */
144 	/*
145 	 * Prevent forking cd, pushd, popd, chdir cause this will cause the
146 	 * shell not to change dir!
147 	 */
148 	if (bifunc && (bifunc->bfunct == dochngd ||
149 		       bifunc->bfunct == dopushd ||
150 		       bifunc->bfunct == dopopd))
151 	    t->t_dflg &= ~(F_NICE);
152 	if (((t->t_dflg & F_TIME) || (t->t_dflg & F_NOFORK) == 0 &&
153 	     (!bifunc || t->t_dflg &
154 	      (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP))) ||
155 	/*
156 	 * We have to fork for eval too.
157 	 */
158 	    (bifunc && (t->t_dflg & F_PIPEIN) != 0 &&
159 	     bifunc->bfunct == doeval))
160 	    if (t->t_dtyp == NODE_PAREN ||
161 		t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) {
162 		forked++;
163 		/*
164 		 * We need to block SIGCHLD here, so that if the process does
165 		 * not die before we can set the process group
166 		 */
167 		if (wanttty >= 0 && !nosigchld) {
168 		    csigmask = sigblock(sigmask(SIGCHLD));
169 		    nosigchld = 1;
170 		}
171 
172 		pid = pfork(t, wanttty);
173 		if (pid == 0 && nosigchld) {
174 		    (void) sigsetmask(csigmask);
175 		    nosigchld = 0;
176 		}
177 	    }
178 	    else {
179 		int     ochild, osetintr, ohaderr, odidfds;
180 		int     oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp;
181 		sigset_t omask;
182 
183 		/*
184 		 * Prepare for the vfork by saving everything that the child
185 		 * corrupts before it exec's. Note that in some signal
186 		 * implementations which keep the signal info in user space
187 		 * (e.g. Sun's) it will also be necessary to save and restore
188 		 * the current sigvec's for the signals the child touches
189 		 * before it exec's.
190 		 */
191 		if (wanttty >= 0 && !nosigchld && !noexec) {
192 		    csigmask = sigblock(sigmask(SIGCHLD));
193 		    nosigchld = 1;
194 		}
195 		omask = sigblock(sigmask(SIGCHLD) | sigmask(SIGINT));
196 		ochild = child;
197 		osetintr = setintr;
198 		ohaderr = haderr;
199 		odidfds = didfds;
200 		oSHIN = SHIN;
201 		oSHOUT = SHOUT;
202 		oSHDIAG = SHDIAG;
203 		oOLDSTD = OLDSTD;
204 		otpgrp = tpgrp;
205 		ocsigmask = csigmask;
206 		onosigchld = nosigchld;
207 		Vsav = Vdp = 0;
208 		Vexpath = 0;
209 		Vt = 0;
210 		pid = vfork();
211 
212 		if (pid < 0) {
213 		    (void) sigsetmask(omask);
214 		    stderror(ERR_NOPROC);
215 		}
216 		forked++;
217 		if (pid) {	/* parent */
218 		    child = ochild;
219 		    setintr = osetintr;
220 		    haderr = ohaderr;
221 		    didfds = odidfds;
222 		    SHIN = oSHIN;
223 		    SHOUT = oSHOUT;
224 		    SHDIAG = oSHDIAG;
225 		    OLDSTD = oOLDSTD;
226 		    tpgrp = otpgrp;
227 		    csigmask = ocsigmask;
228 		    nosigchld = onosigchld;
229 
230 		    xfree((ptr_t) Vsav);
231 		    Vsav = 0;
232 		    xfree((ptr_t) Vdp);
233 		    Vdp = 0;
234 		    xfree((ptr_t) Vexpath);
235 		    Vexpath = 0;
236 		    blkfree((Char **) Vt);
237 		    Vt = 0;
238 		    /* this is from pfork() */
239 		    palloc(pid, t);
240 		    (void) sigsetmask(omask);
241 		}
242 		else {		/* child */
243 		    /* this is from pfork() */
244 		    int     pgrp;
245 		    bool    ignint = 0;
246 
247 		    if (nosigchld) {
248 			(void) sigsetmask(csigmask);
249 			nosigchld = 0;
250 		    }
251 
252 		    if (setintr)
253 			ignint =
254 			    (tpgrp == -1 &&
255 			     (t->t_dflg & F_NOINTERRUPT))
256 			    || gointr && eq(gointr, STRminus);
257 		    pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
258 		    child++;
259 		    if (setintr) {
260 			setintr = 0;
261 			if (ignint) {
262 			    (void) signal(SIGINT, SIG_IGN);
263 			    (void) signal(SIGQUIT, SIG_IGN);
264 			}
265 			else {
266 			    (void) signal(SIGINT, vffree);
267 			    (void) signal(SIGQUIT, SIG_DFL);
268 			}
269 
270 			if (wanttty >= 0) {
271 			    (void) signal(SIGTSTP, SIG_DFL);
272 			    (void) signal(SIGTTIN, SIG_DFL);
273 			    (void) signal(SIGTTOU, SIG_DFL);
274 			}
275 
276 			(void) signal(SIGTERM, parterm);
277 		    }
278 		    else if (tpgrp == -1 &&
279 			     (t->t_dflg & F_NOINTERRUPT)) {
280 			(void) signal(SIGINT, SIG_IGN);
281 			(void) signal(SIGQUIT, SIG_IGN);
282 		    }
283 
284 		    pgetty(wanttty, pgrp);
285 		    if (t->t_dflg & F_NOHUP)
286 			(void) signal(SIGHUP, SIG_IGN);
287 		    if (t->t_dflg & F_NICE)
288 			(void) setpriority(PRIO_PROCESS, 0, t->t_nice);
289 		}
290 
291 	    }
292 	if (pid != 0) {
293 	    /*
294 	     * It would be better if we could wait for the whole job when we
295 	     * knew the last process had been started.  Pwait, in fact, does
296 	     * wait for the whole job anyway, but this test doesn't really
297 	     * express our intentions.
298 	     */
299 	    if (didfds == 0 && t->t_dflg & F_PIPEIN) {
300 		(void) close(pipein[0]);
301 		(void) close(pipein[1]);
302 	    }
303 	    if ((t->t_dflg & F_PIPEOUT) == 0) {
304 		if (nosigchld) {
305 		    (void) sigsetmask(csigmask);
306 		    nosigchld = 0;
307 		}
308 		if ((t->t_dflg & F_AMPERSAND) == 0)
309 		    pwait();
310 	    }
311 	    break;
312 	}
313 	doio(t, pipein, pipeout);
314 	if (t->t_dflg & F_PIPEOUT) {
315 	    (void) close(pipeout[0]);
316 	    (void) close(pipeout[1]);
317 	}
318 	/*
319 	 * Perform a builtin function. If we are not forked, arrange for
320 	 * possible stopping
321 	 */
322 	if (bifunc) {
323 	    func(t, bifunc);
324 	    if (forked)
325 		exitstat();
326 	    break;
327 	}
328 	if (t->t_dtyp != NODE_PAREN) {
329 	    doexec(t);
330 	    /* NOTREACHED */
331 	}
332 	/*
333 	 * For () commands must put new 0,1,2 in FSH* and recurse
334 	 */
335 	OLDSTD = dcopy(0, FOLDSTD);
336 	SHOUT = dcopy(1, FSHOUT);
337 	SHDIAG = dcopy(2, FSHDIAG);
338 	(void) close(SHIN);
339 	SHIN = -1;
340 	didfds = 0;
341 	wanttty = -1;
342 	t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT;
343 	execute(t->t_dspr, wanttty, NULL, NULL);
344 	exitstat();
345 
346     case NODE_PIPE:
347 	t->t_dcar->t_dflg |= F_PIPEOUT |
348 	    (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT));
349 	execute(t->t_dcar, wanttty, pipein, pv);
350 	t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
351 			(F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT));
352 	if (wanttty > 0)
353 	    wanttty = 0;	/* got tty already */
354 	execute(t->t_dcdr, wanttty, pv, pipeout);
355 	break;
356 
357     case NODE_LIST:
358 	if (t->t_dcar) {
359 	    t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
360 	    execute(t->t_dcar, wanttty, NULL, NULL);
361 	    /*
362 	     * In strange case of A&B make a new job after A
363 	     */
364 	    if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr &&
365 		(t->t_dcdr->t_dflg & F_AMPERSAND) == 0)
366 		pendjob();
367 	}
368 	if (t->t_dcdr) {
369 	    t->t_dcdr->t_dflg |= t->t_dflg &
370 		(F_NOFORK | F_NOINTERRUPT);
371 	    execute(t->t_dcdr, wanttty, NULL, NULL);
372 	}
373 	break;
374 
375     case NODE_OR:
376     case NODE_AND:
377 	if (t->t_dcar) {
378 	    t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
379 	    execute(t->t_dcar, wanttty, NULL, NULL);
380 	    if ((getn(value(STRstatus)) == 0) !=
381 		(t->t_dtyp == NODE_AND))
382 		return;
383 	}
384 	if (t->t_dcdr) {
385 	    t->t_dcdr->t_dflg |= t->t_dflg &
386 		(F_NOFORK | F_NOINTERRUPT);
387 	    execute(t->t_dcdr, wanttty, NULL, NULL);
388 	}
389 	break;
390     }
391     /*
392      * Fall through for all breaks from switch
393      *
394      * If there will be no more executions of this command, flush all file
395      * descriptors. Places that turn on the F_REPEAT bit are responsible for
396      * doing donefds after the last re-execution
397      */
398     if (didfds && !(t->t_dflg & F_REPEAT))
399 	donefds();
400 }
401 
402 static void
403 vffree(i)
404 int i;
405 {
406     register Char **v;
407 
408     if (v = gargv) {
409 	gargv = 0;
410 	xfree((ptr_t) v);
411     }
412     if (v = pargv) {
413 	pargv = 0;
414 	xfree((ptr_t) v);
415     }
416     _exit(i);
417 }
418 
419 /*
420  * Perform io redirection.
421  * We may or maynot be forked here.
422  */
423 static void
424 doio(t, pipein, pipeout)
425     register struct command *t;
426     int    *pipein, *pipeout;
427 {
428     register int fd;
429     register Char *cp;
430     register int flags = t->t_dflg;
431 
432     if (didfds || (flags & F_REPEAT))
433 	return;
434     if ((flags & F_READ) == 0) {/* F_READ already done */
435 	if (cp = t->t_dlef) {
436 	    char    tmp[MAXPATHLEN+1];
437 
438 	    /*
439 	     * so < /dev/std{in,out,err} work
440 	     */
441 	    (void) dcopy(SHIN, 0);
442 	    (void) dcopy(SHOUT, 1);
443 	    (void) dcopy(SHDIAG, 2);
444 	    cp = globone(Dfix1(cp), G_IGNORE);
445 	    (void) strncpy(tmp, short2str(cp), MAXPATHLEN);
446 	    tmp[MAXPATHLEN] = '\0';
447 	    xfree((ptr_t) cp);
448 	    if ((fd = open(tmp, O_RDONLY)) < 0)
449 		stderror(ERR_SYSTEM, tmp, strerror(errno));
450 	    (void) dmove(fd, 0);
451 	}
452 	else if (flags & F_PIPEIN) {
453 	    (void) close(0);
454 	    (void) dup(pipein[0]);
455 	    (void) close(pipein[0]);
456 	    (void) close(pipein[1]);
457 	}
458 	else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
459 	    (void) close(0);
460 	    (void) open(_PATH_DEVNULL, O_RDONLY);
461 	}
462 	else {
463 	    (void) close(0);
464 	    (void) dup(OLDSTD);
465 	    (void) ioctl(0, FIONCLEX, NULL);
466 	}
467     }
468     if (cp = t->t_drit) {
469 	char    tmp[MAXPATHLEN+1];
470 
471 	cp = globone(Dfix1(cp), G_IGNORE);
472 	(void) strncpy(tmp, short2str(cp), MAXPATHLEN);
473 	tmp[MAXPATHLEN] = '\0';
474 	xfree((ptr_t) cp);
475 	/*
476 	 * so > /dev/std{out,err} work
477 	 */
478 	(void) dcopy(SHOUT, 1);
479 	(void) dcopy(SHDIAG, 2);
480 	if ((flags & F_APPEND) &&
481 #ifdef O_APPEND
482 	    (fd = open(tmp, O_WRONLY | O_APPEND)) >= 0);
483 #else
484 	    (fd = open(tmp, O_WRONLY)) >= 0)
485 	    (void) lseek(1, (off_t) 0, L_XTND);
486 #endif
487 	else {
488 	    if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) {
489 		if (flags & F_APPEND)
490 		    stderror(ERR_SYSTEM, tmp, strerror(errno));
491 		chkclob(tmp);
492 	    }
493 	    if ((fd = creat(tmp, 0666)) < 0)
494 		stderror(ERR_SYSTEM, tmp, strerror(errno));
495 	}
496 	(void) dmove(fd, 1);
497     }
498     else if (flags & F_PIPEOUT) {
499 	(void) close(1);
500 	(void) dup(pipeout[1]);
501     }
502     else {
503 	(void) close(1);
504 	(void) dup(SHOUT);
505 	(void) ioctl(1, FIONCLEX, NULL);
506     }
507 
508     (void) close(2);
509     if (flags & F_STDERR) {
510 	(void) dup(1);
511     }
512     else {
513 	(void) dup(SHDIAG);
514 	(void) ioctl(2, FIONCLEX, NULL);
515     }
516     didfds = 1;
517 }
518 
519 void
520 mypipe(pv)
521     register int *pv;
522 {
523 
524     if (pipe(pv) < 0)
525 	goto oops;
526     pv[0] = dmove(pv[0], -1);
527     pv[1] = dmove(pv[1], -1);
528     if (pv[0] >= 0 && pv[1] >= 0)
529 	return;
530 oops:
531     stderror(ERR_PIPE);
532 }
533 
534 static void
535 chkclob(cp)
536     register char *cp;
537 {
538     struct stat stb;
539 
540     if (stat(cp, &stb) < 0)
541 	return;
542     if ((stb.st_mode & S_IFMT) == S_IFCHR)
543 	return;
544     stderror(ERR_EXISTS, cp);
545 }
546