xref: /netbsd-src/bin/csh/sem.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
1 /*-
2  * Copyright (c) 1980, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 /*static char sccsid[] = "from: @(#)sem.c	8.1 (Berkeley) 5/31/93";*/
36 static char *rcsid = "$Id: sem.c,v 1.6 1994/09/23 11:16:37 mycroft Exp $";
37 #endif /* not lint */
38 
39 #include <sys/param.h>
40 #include <sys/ioctl.h>
41 #include <sys/stat.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #if __STDC__
48 # include <stdarg.h>
49 #else
50 # include <varargs.h>
51 #endif
52 
53 #include "csh.h"
54 #include "proc.h"
55 #include "extern.h"
56 
57 static void	 vffree __P((int));
58 static Char	*splicepipe __P((struct command *t, Char *));
59 static void	 doio __P((struct command *t, int *, int *));
60 static void	 chkclob __P((char *));
61 
62 void
63 execute(t, wanttty, pipein, pipeout)
64     register struct command *t;
65     int     wanttty, *pipein, *pipeout;
66 {
67     bool    forked = 0;
68     struct biltins *bifunc;
69     int     pid = 0;
70     int     pv[2];
71 
72     static sigset_t csigmask;
73 
74     static sigset_t ocsigmask;
75     static int onosigchld = 0;
76     static int nosigchld = 0;
77 
78     UNREGISTER(forked);
79     UNREGISTER(bifunc);
80     UNREGISTER(wanttty);
81 
82     if (t == 0)
83 	return;
84 
85     if (t->t_dflg & F_AMPERSAND)
86 	wanttty = 0;
87     switch (t->t_dtyp) {
88 
89     case NODE_COMMAND:
90 	if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
91 	    (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
92 	if ((t->t_dflg & F_REPEAT) == 0)
93 	    Dfix(t);		/* $ " ' \ */
94 	if (t->t_dcom[0] == 0)
95 	    return;
96 	/* fall into... */
97 
98     case NODE_PAREN:
99 	if (t->t_dflg & F_PIPEOUT)
100 	    mypipe(pipeout);
101 	/*
102 	 * Must do << early so parent will know where input pointer should be.
103 	 * If noexec then this is all we do.
104 	 */
105 	if (t->t_dflg & F_READ) {
106 	    (void) close(0);
107 	    heredoc(t->t_dlef);
108 	    if (noexec)
109 		(void) close(0);
110 	}
111 
112 	set(STRstatus, Strsave(STR0));
113 
114 	/*
115 	 * This mess is the necessary kludge to handle the prefix builtins:
116 	 * nice, nohup, time.  These commands can also be used by themselves,
117 	 * and this is not handled here. This will also work when loops are
118 	 * parsed.
119 	 */
120 	while (t->t_dtyp == NODE_COMMAND)
121 	    if (eq(t->t_dcom[0], STRnice))
122 		if (t->t_dcom[1])
123 		    if (strchr("+-", t->t_dcom[1][0]))
124 			if (t->t_dcom[2]) {
125 			    setname("nice");
126 			    t->t_nice =
127 				getn(t->t_dcom[1]);
128 			    lshift(t->t_dcom, 2);
129 			    t->t_dflg |= F_NICE;
130 			}
131 			else
132 			    break;
133 		    else {
134 			t->t_nice = 4;
135 			lshift(t->t_dcom, 1);
136 			t->t_dflg |= F_NICE;
137 		    }
138 		else
139 		    break;
140 	    else if (eq(t->t_dcom[0], STRnohup))
141 		if (t->t_dcom[1]) {
142 		    t->t_dflg |= F_NOHUP;
143 		    lshift(t->t_dcom, 1);
144 		}
145 		else
146 		    break;
147 	    else if (eq(t->t_dcom[0], STRtime))
148 		if (t->t_dcom[1]) {
149 		    t->t_dflg |= F_TIME;
150 		    lshift(t->t_dcom, 1);
151 		}
152 		else
153 		    break;
154 	    else
155 		break;
156 
157 	/* is it a command */
158 	if (t->t_dtyp == NODE_COMMAND) {
159 	    /*
160 	     * Check if we have a builtin function and remember which one.
161 	     */
162 	    bifunc = isbfunc(t);
163  	    if (noexec) {
164 		/*
165 		 * Continue for builtins that are part of the scripting language
166 		 */
167 		if (bifunc->bfunct != dobreak   && bifunc->bfunct != docontin &&
168 		    bifunc->bfunct != doelse    && bifunc->bfunct != doend    &&
169 		    bifunc->bfunct != doforeach && bifunc->bfunct != dogoto   &&
170 		    bifunc->bfunct != doif      && bifunc->bfunct != dorepeat &&
171 		    bifunc->bfunct != doswbrk   && bifunc->bfunct != doswitch &&
172 		    bifunc->bfunct != dowhile   && bifunc->bfunct != dozip)
173 		    break;
174 	    }
175 	}
176 	else {			/* not a command */
177 	    bifunc = NULL;
178 	    if (noexec)
179 		break;
180 	}
181 
182 	/*
183 	 * We fork only if we are timed, or are not the end of a parenthesized
184 	 * list and not a simple builtin function. Simple meaning one that is
185 	 * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not
186 	 * fork in some of these cases.
187 	 */
188 	/*
189 	 * Prevent forking cd, pushd, popd, chdir cause this will cause the
190 	 * shell not to change dir!
191 	 */
192 	if (bifunc && (bifunc->bfunct == dochngd ||
193 		       bifunc->bfunct == dopushd ||
194 		       bifunc->bfunct == dopopd))
195 	    t->t_dflg &= ~(F_NICE);
196 	if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 &&
197 	     (!bifunc || t->t_dflg &
198 	      (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP)))) ||
199 	/*
200 	 * We have to fork for eval too.
201 	 */
202 	    (bifunc && (t->t_dflg & (F_PIPEIN | F_PIPEOUT)) != 0 &&
203 	     bifunc->bfunct == doeval))
204 	    if (t->t_dtyp == NODE_PAREN ||
205 		t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) {
206 		forked++;
207 		/*
208 		 * We need to block SIGCHLD here, so that if the process does
209 		 * not die before we can set the process group
210 		 */
211 		if (wanttty >= 0 && !nosigchld) {
212 		    csigmask = sigblock(sigmask(SIGCHLD));
213 		    nosigchld = 1;
214 		}
215 
216 		pid = pfork(t, wanttty);
217 		if (pid == 0 && nosigchld) {
218 		    (void) sigsetmask(csigmask);
219 		    nosigchld = 0;
220 		}
221 		else if (pid != 0 && (t->t_dflg & F_AMPERSAND))
222 		    backpid = pid;
223 
224 	    }
225 	    else {
226 		int     ochild, osetintr, ohaderr, odidfds;
227 		int     oSHIN, oSHOUT, oSHERR, oOLDSTD, otpgrp;
228 		sigset_t omask;
229 
230 		/*
231 		 * Prepare for the vfork by saving everything that the child
232 		 * corrupts before it exec's. Note that in some signal
233 		 * implementations which keep the signal info in user space
234 		 * (e.g. Sun's) it will also be necessary to save and restore
235 		 * the current sigvec's for the signals the child touches
236 		 * before it exec's.
237 		 */
238 		if (wanttty >= 0 && !nosigchld && !noexec) {
239 		    csigmask = sigblock(sigmask(SIGCHLD));
240 		    nosigchld = 1;
241 		}
242 		omask = sigblock(sigmask(SIGCHLD) | sigmask(SIGINT));
243 		ochild = child;
244 		osetintr = setintr;
245 		ohaderr = haderr;
246 		odidfds = didfds;
247 		oSHIN = SHIN;
248 		oSHOUT = SHOUT;
249 		oSHERR = SHERR;
250 		oOLDSTD = OLDSTD;
251 		otpgrp = tpgrp;
252 		ocsigmask = csigmask;
253 		onosigchld = nosigchld;
254 		Vsav = Vdp = 0;
255 		Vexpath = 0;
256 		Vt = 0;
257 		pid = vfork();
258 
259 		if (pid < 0) {
260 		    (void) sigsetmask(omask);
261 		    stderror(ERR_NOPROC);
262 		}
263 		forked++;
264 		if (pid) {	/* parent */
265 		    child = ochild;
266 		    setintr = osetintr;
267 		    haderr = ohaderr;
268 		    didfds = odidfds;
269 		    SHIN = oSHIN;
270 		    SHOUT = oSHOUT;
271 		    SHERR = oSHERR;
272 		    OLDSTD = oOLDSTD;
273 		    tpgrp = otpgrp;
274 		    csigmask = ocsigmask;
275 		    nosigchld = onosigchld;
276 
277 		    xfree((ptr_t) Vsav);
278 		    Vsav = 0;
279 		    xfree((ptr_t) Vdp);
280 		    Vdp = 0;
281 		    xfree((ptr_t) Vexpath);
282 		    Vexpath = 0;
283 		    blkfree((Char **) Vt);
284 		    Vt = 0;
285 		    /* this is from pfork() */
286 		    palloc(pid, t);
287 		    (void) sigsetmask(omask);
288 		}
289 		else {		/* child */
290 		    /* this is from pfork() */
291 		    int     pgrp;
292 		    bool    ignint = 0;
293 
294 		    if (nosigchld) {
295 			(void) sigsetmask(csigmask);
296 			nosigchld = 0;
297 		    }
298 
299 		    if (setintr)
300 			ignint =
301 			    (tpgrp == -1 &&
302 			     (t->t_dflg & F_NOINTERRUPT))
303 			    || (gointr && eq(gointr, STRminus));
304 		    pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
305 		    child++;
306 		    if (setintr) {
307 			setintr = 0;
308 			if (ignint) {
309 			    (void) signal(SIGINT, SIG_IGN);
310 			    (void) signal(SIGQUIT, SIG_IGN);
311 			}
312 			else {
313 			    (void) signal(SIGINT, vffree);
314 			    (void) signal(SIGQUIT, SIG_DFL);
315 			}
316 
317 			if (wanttty >= 0) {
318 			    (void) signal(SIGTSTP, SIG_DFL);
319 			    (void) signal(SIGTTIN, SIG_DFL);
320 			    (void) signal(SIGTTOU, SIG_DFL);
321 			}
322 
323 			(void) signal(SIGTERM, parterm);
324 		    }
325 		    else if (tpgrp == -1 &&
326 			     (t->t_dflg & F_NOINTERRUPT)) {
327 			(void) signal(SIGINT, SIG_IGN);
328 			(void) signal(SIGQUIT, SIG_IGN);
329 		    }
330 
331 		    pgetty(wanttty, pgrp);
332 		    if (t->t_dflg & F_NOHUP)
333 			(void) signal(SIGHUP, SIG_IGN);
334 		    if (t->t_dflg & F_NICE)
335 			(void) setpriority(PRIO_PROCESS, 0, t->t_nice);
336 		}
337 
338 	    }
339 	if (pid != 0) {
340 	    /*
341 	     * It would be better if we could wait for the whole job when we
342 	     * knew the last process had been started.  Pwait, in fact, does
343 	     * wait for the whole job anyway, but this test doesn't really
344 	     * express our intentions.
345 	     */
346 	    if (didfds == 0 && t->t_dflg & F_PIPEIN) {
347 		(void) close(pipein[0]);
348 		(void) close(pipein[1]);
349 	    }
350 	    if ((t->t_dflg & F_PIPEOUT) == 0) {
351 		if (nosigchld) {
352 		    (void) sigsetmask(csigmask);
353 		    nosigchld = 0;
354 		}
355 		if ((t->t_dflg & F_AMPERSAND) == 0)
356 		    pwait();
357 	    }
358 	    break;
359 	}
360 	doio(t, pipein, pipeout);
361 	if (t->t_dflg & F_PIPEOUT) {
362 	    (void) close(pipeout[0]);
363 	    (void) close(pipeout[1]);
364 	}
365 	/*
366 	 * Perform a builtin function. If we are not forked, arrange for
367 	 * possible stopping
368 	 */
369 	if (bifunc) {
370 	    func(t, bifunc);
371 	    if (forked)
372 		exitstat();
373 	    break;
374 	}
375 	if (t->t_dtyp != NODE_PAREN) {
376 	    doexec(NULL, t);
377 	    /* NOTREACHED */
378 	}
379 	/*
380 	 * For () commands must put new 0,1,2 in FSH* and recurse
381 	 */
382 	OLDSTD = dcopy(0, FOLDSTD);
383 	SHOUT = dcopy(1, FSHOUT);
384 	SHERR = dcopy(2, FSHERR);
385 	(void) close(SHIN);
386 	SHIN = -1;
387 	didfds = 0;
388 	wanttty = -1;
389 	t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT;
390 	execute(t->t_dspr, wanttty, NULL, NULL);
391 	exitstat();
392 
393     case NODE_PIPE:
394 	t->t_dcar->t_dflg |= F_PIPEOUT |
395 	    (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT));
396 	execute(t->t_dcar, wanttty, pipein, pv);
397 	t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
398 			(F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT));
399 	if (wanttty > 0)
400 	    wanttty = 0;	/* got tty already */
401 	execute(t->t_dcdr, wanttty, pv, pipeout);
402 	break;
403 
404     case NODE_LIST:
405 	if (t->t_dcar) {
406 	    t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
407 	    execute(t->t_dcar, wanttty, NULL, NULL);
408 	    /*
409 	     * In strange case of A&B make a new job after A
410 	     */
411 	    if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr &&
412 		(t->t_dcdr->t_dflg & F_AMPERSAND) == 0)
413 		pendjob();
414 	}
415 	if (t->t_dcdr) {
416 	    t->t_dcdr->t_dflg |= t->t_dflg &
417 		(F_NOFORK | F_NOINTERRUPT);
418 	    execute(t->t_dcdr, wanttty, NULL, NULL);
419 	}
420 	break;
421 
422     case NODE_OR:
423     case NODE_AND:
424 	if (t->t_dcar) {
425 	    t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
426 	    execute(t->t_dcar, wanttty, NULL, NULL);
427 	    if ((getn(value(STRstatus)) == 0) !=
428 		(t->t_dtyp == NODE_AND))
429 		return;
430 	}
431 	if (t->t_dcdr) {
432 	    t->t_dcdr->t_dflg |= t->t_dflg &
433 		(F_NOFORK | F_NOINTERRUPT);
434 	    execute(t->t_dcdr, wanttty, NULL, NULL);
435 	}
436 	break;
437     }
438     /*
439      * Fall through for all breaks from switch
440      *
441      * If there will be no more executions of this command, flush all file
442      * descriptors. Places that turn on the F_REPEAT bit are responsible for
443      * doing donefds after the last re-execution
444      */
445     if (didfds && !(t->t_dflg & F_REPEAT))
446 	donefds();
447 }
448 
449 static void
450 vffree(i)
451 int i;
452 {
453     register Char **v;
454 
455     if ((v = gargv) != NULL) {
456 	gargv = 0;
457 	xfree((ptr_t) v);
458     }
459     if ((v = pargv) != NULL) {
460 	pargv = 0;
461 	xfree((ptr_t) v);
462     }
463     _exit(i);
464 }
465 
466 /*
467  * Expand and glob the words after an i/o redirection.
468  * If more than one word is generated, then update the command vector.
469  *
470  * This is done differently in all the shells:
471  * 1. in the bourne shell and ksh globbing is not performed
472  * 2. Bash/csh say ambiguous
473  * 3. zsh does i/o to/from all the files
474  * 4. itcsh concatenates the words.
475  *
476  * I don't know what is best to do. I think that Ambiguous is better
477  * than restructuring the command vector, because the user can get
478  * unexpected results. In any case, the command vector restructuring
479  * code is present and the user can choose it by setting noambiguous
480  */
481 static Char *
482 splicepipe(t, cp)
483     register struct command *t;
484     Char *cp;	/* word after < or > */
485 {
486     Char *blk[2];
487 
488     if (adrof(STRnoambiguous)) {
489 	Char **pv;
490 
491 	blk[0] = Dfix1(cp); /* expand $ */
492 	blk[1] = NULL;
493 
494 	gflag = 0, tglob(blk);
495 	if (gflag) {
496 	    pv = globall(blk);
497 	    if (pv == NULL) {
498 		setname(vis_str(blk[0]));
499 		xfree((ptr_t) blk[0]);
500 		stderror(ERR_NAME | ERR_NOMATCH);
501 	    }
502 	    gargv = NULL;
503 	    if (pv[1] != NULL) { /* we need to fix the command vector */
504 		Char **av = blkspl(t->t_dcom, &pv[1]);
505 		xfree((ptr_t) t->t_dcom);
506 		t->t_dcom = av;
507 	    }
508 	    xfree((ptr_t) blk[0]);
509 	    blk[0] = pv[0];
510 	    xfree((ptr_t) pv);
511 	}
512     }
513     else {
514 	blk[0] = globone(blk[1] = Dfix1(cp), G_ERROR);
515 	xfree((ptr_t) blk[1]);
516     }
517     return(blk[0]);
518 }
519 
520 /*
521  * Perform io redirection.
522  * We may or maynot be forked here.
523  */
524 static void
525 doio(t, pipein, pipeout)
526     register struct command *t;
527     int    *pipein, *pipeout;
528 {
529     register int fd;
530     register Char *cp;
531     register int flags = t->t_dflg;
532 
533     if (didfds || (flags & F_REPEAT))
534 	return;
535     if ((flags & F_READ) == 0) {/* F_READ already done */
536 	if (t->t_dlef) {
537 	    char    tmp[MAXPATHLEN+1];
538 
539 	    /*
540 	     * so < /dev/std{in,out,err} work
541 	     */
542 	    (void) dcopy(SHIN, 0);
543 	    (void) dcopy(SHOUT, 1);
544 	    (void) dcopy(SHERR, 2);
545 	    cp = splicepipe(t, t->t_dlef);
546 	    (void) strncpy(tmp, short2str(cp), MAXPATHLEN);
547 	    tmp[MAXPATHLEN] = '\0';
548 	    xfree((ptr_t) cp);
549 	    if ((fd = open(tmp, O_RDONLY)) < 0)
550 		stderror(ERR_SYSTEM, tmp, strerror(errno));
551 	    (void) dmove(fd, 0);
552 	}
553 	else if (flags & F_PIPEIN) {
554 	    (void) close(0);
555 	    (void) dup(pipein[0]);
556 	    (void) close(pipein[0]);
557 	    (void) close(pipein[1]);
558 	}
559 	else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
560 	    (void) close(0);
561 	    (void) open(_PATH_DEVNULL, O_RDONLY);
562 	}
563 	else {
564 	    (void) close(0);
565 	    (void) dup(OLDSTD);
566 	    (void) ioctl(0, FIONCLEX, NULL);
567 	}
568     }
569     if (t->t_drit) {
570 	char    tmp[MAXPATHLEN+1];
571 
572 	cp = splicepipe(t, t->t_drit);
573 	(void) strncpy(tmp, short2str(cp), MAXPATHLEN);
574 	tmp[MAXPATHLEN] = '\0';
575 	xfree((ptr_t) cp);
576 	/*
577 	 * so > /dev/std{out,err} work
578 	 */
579 	(void) dcopy(SHOUT, 1);
580 	(void) dcopy(SHERR, 2);
581 	if ((flags & F_APPEND) &&
582 #ifdef O_APPEND
583 	    (fd = open(tmp, O_WRONLY | O_APPEND)) >= 0);
584 #else
585 	    (fd = open(tmp, O_WRONLY)) >= 0)
586 	    (void) lseek(1, (off_t) 0, L_XTND);
587 #endif
588 	else {
589 	    if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) {
590 		if (flags & F_APPEND)
591 		    stderror(ERR_SYSTEM, tmp, strerror(errno));
592 		chkclob(tmp);
593 	    }
594 	    if ((fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
595 		stderror(ERR_SYSTEM, tmp, strerror(errno));
596 	}
597 	(void) dmove(fd, 1);
598     }
599     else if (flags & F_PIPEOUT) {
600 	(void) close(1);
601 	(void) dup(pipeout[1]);
602     }
603     else {
604 	(void) close(1);
605 	(void) dup(SHOUT);
606 	(void) ioctl(1, FIONCLEX, NULL);
607     }
608 
609     (void) close(2);
610     if (flags & F_STDERR) {
611 	(void) dup(1);
612     }
613     else {
614 	(void) dup(SHERR);
615 	(void) ioctl(2, FIONCLEX, NULL);
616     }
617     didfds = 1;
618 }
619 
620 void
621 mypipe(pv)
622     register int *pv;
623 {
624 
625     if (pipe(pv) < 0)
626 	goto oops;
627     pv[0] = dmove(pv[0], -1);
628     pv[1] = dmove(pv[1], -1);
629     if (pv[0] >= 0 && pv[1] >= 0)
630 	return;
631 oops:
632     stderror(ERR_PIPE);
633 }
634 
635 static void
636 chkclob(cp)
637     register char *cp;
638 {
639     struct stat stb;
640 
641     if (stat(cp, &stb) < 0)
642 	return;
643     if (S_ISCHR(stb.st_mode))
644 	return;
645     stderror(ERR_EXISTS, cp);
646 }
647