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