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