Merge commit '00f1a4f432b3d8aad1aa270e91c44c57f03ef407'
[unleashed.git] / usr / src / cmd / csh / sh.sem.c
blobbf4d47f21bf9f68ab2dabbc7a2d8c35efbef6eb0
1 /*
2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
9 /*
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley Software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include "sh.h"
20 #include "sh.proc.h"
21 #include "sh.tconst.h"
24 * C shell
27 void doio(struct command *, int *, int *);
28 void mypipe(int *);
29 void chkclob(tchar *);
32 * Return true if there is a back-quote (`) anywhere in the argument list.
33 * Its presence would cause glob() to be invoked in the child process
34 * and this would cause chaos if the child is created with vfork().
36 static bool
37 AnyBquote(struct command *t)
39 tchar **pp;
40 tchar *p;
42 if (noexec)
43 return (0);
44 for (pp = t->t_dcom; p = *pp++;) {
45 if (any('`', p))
46 return (1);
48 return (0);
51 /*VARARGS 1*/
52 void
53 execute(t, wanttty, pipein, pipeout)
54 struct command *t;
55 int wanttty, *pipein, *pipeout;
57 bool forked = 0;
58 struct biltins *bifunc;
59 int pid = 0;
60 int pv[2];
61 extern int globcnt;
62 #ifdef TRACE
63 tprintf("TRACE- execute()\n");
64 #endif
66 if (t == 0)
67 return;
68 if ((t->t_dflg & FAND) && wanttty > 0)
69 wanttty = 0;
70 switch (t->t_dtyp) {
72 case TCOM:
73 if (t->t_dcom[0][0] == (tchar)S_TOPBIT[0])
74 (void) strcpy_(t->t_dcom[0], t->t_dcom[0] + 1);
75 if ((t->t_dflg & FREDO) == 0)
76 Dfix(t); /* $ " ' \ */
77 if (t->t_dcom[0] == 0)
78 return;
79 /* fall into... */
81 case TPAR:
82 if (t->t_dflg & FPOU)
83 mypipe(pipeout);
85 * Must do << early so parent will know
86 * where input pointer should be.
87 * If noexec then this is all we do.
89 if (t->t_dflg & FHERE) {
90 (void) close(0);
91 unsetfd(0);
92 heredoc(t->t_dlef);
93 if (noexec) {
94 (void) close(0);
95 unsetfd(0);
98 if (noexec)
99 break;
101 set(S_status, S_0);
104 * This mess is the necessary kludge to handle the prefix
105 * builtins: nice, nohup, time. These commands can also
106 * be used by themselves, and this is not handled here.
107 * This will also work when loops are parsed.
109 while (t->t_dtyp == TCOM)
110 if (eq(t->t_dcom[0], S_nice /*"nice"*/))
111 if (t->t_dcom[1])
112 /*if (any(t->t_dcom[1][0], "+-"))*/
113 if (t->t_dcom[1][0] == '+' ||
114 t->t_dcom[1][0] == '-')
115 if (t->t_dcom[2]) {
116 setname(S_nice /*"nice"*/);
117 t->t_nice = getn(t->t_dcom[1]);
118 lshift(t->t_dcom, 2);
119 t->t_dflg |= FNICE;
120 } else
121 break;
122 else {
123 t->t_nice = 4;
124 lshift(t->t_dcom, 1);
125 t->t_dflg |= FNICE;
127 else
128 break;
129 else if (eq(t->t_dcom[0], S_nohup /*"nohup"*/))
130 if (t->t_dcom[1]) {
131 t->t_dflg |= FNOHUP;
132 lshift(t->t_dcom, 1);
133 } else
134 break;
135 else if (eq(t->t_dcom[0], S_time /*"time"*/))
136 if (t->t_dcom[1]) {
137 t->t_dflg |= FTIME;
138 lshift(t->t_dcom, 1);
139 } else
140 break;
141 else
142 break;
144 * Check if we have a builtin function and remember which one.
146 bifunc = t->t_dtyp == TCOM ? isbfunc(t) : NULL;
149 * We fork only if we are timed, or are not the end of
150 * a parenthesized list and not a simple builtin function.
151 * Simple meaning one that is not pipedout, niced, nohupped,
152 * or &'d.
153 * It would be nice(?) to not fork in some of these cases.
155 if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 &&
156 (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP))))
157 #ifdef VFORK
158 if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) ||
159 bifunc || AnyBquote(t))
160 #endif
161 { forked++; pid = pfork(t, wanttty); }
162 #ifdef VFORK
163 else {
164 void vffree();
165 struct sv {
166 int mask, child, setintr, haderr, didfds;
167 int SHIN, SHOUT, SHDIAG, OLDSTD, tpgrp;
168 struct sigvec sigv;
169 } sv;
172 * Prepare for the vfork by saving everything
173 * that the child corrupts before it exec's.
174 * Note that in some signal implementations
175 * which keep the signal info in user space
176 * (e.g. Sun's) it will also be necessary to
177 * save and restore the current sigvec's for
178 * the signals the child touches before it
179 * exec's.
181 sv.mask = sigblock(sigmask(SIGCHLD));
182 sv.child = child; sv.setintr = setintr;
183 sv.haderr = haderr; sv.didfds = didfds;
184 sv.SHIN = SHIN; sv.SHOUT = SHOUT;
185 sv.SHDIAG = SHDIAG; sv.OLDSTD = OLDSTD;
186 sv.tpgrp = tpgrp;
187 Vsav = Vdp = 0; Vav = 0;
188 (void) sigvec(SIGINT, NULL, &sv.sigv);
189 pid = vfork();
190 if (pid < 0) {
191 (void) sigsetmask(sv.mask);
192 error("Vfork failed");
194 forked++;
195 if (pid) { /* parent */
196 int ppid;
197 closelog();
198 child = sv.child; setintr = sv.setintr;
199 haderr = sv.haderr; didfds = sv.didfds;
200 SHIN = sv.SHIN;
201 SHOUT = sv.SHOUT; SHDIAG = sv.SHDIAG;
202 OLDSTD = sv.OLDSTD; tpgrp = sv.tpgrp;
203 xfree(Vsav); Vsav = 0;
204 xfree(Vdp); Vdp = 0;
205 xfree( (tchar *)Vav); Vav = 0;
206 /* this is from pfork() */
207 ppid = pcurrjob ? pcurrjob->p_jobid : pid;
208 if (wanttty >= 0 && tpgrp >= 0)
209 setpgid (ppid, ppid);
210 palloc(pid, t);
212 * Restore SIGINT handler.
214 (void) sigvec(SIGINT, &sv.sigv, NULL);
215 (void) sigsetmask(sv.mask);
216 } else { /* child */
217 /* this is from pfork() */
218 int pgrp;
219 bool ignint = 0;
220 int sigttou;
221 if (setintr)
222 ignint =
223 (tpgrp == -1 && (t->t_dflg&FINT))
224 || gointr
225 && eq(gointr, S_MINUS/*"-"*/);
226 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
227 child++;
228 if (setintr) {
229 setintr = 0;
230 #ifdef notdef
231 (void) signal(SIGCHLD, SIG_DFL);
232 #endif
233 (void) signal(SIGINT, ignint ?
234 SIG_IGN : vffree);
235 (void) signal(SIGQUIT, ignint ?
236 SIG_IGN : SIG_DFL);
237 if (wanttty >= 0) {
238 (void) signal(SIGTSTP, SIG_DFL);
239 (void) signal(SIGTTIN, SIG_DFL);
240 (void) signal(SIGTTOU, SIG_DFL);
242 (void) signal(SIGTERM, parterm);
243 } else if (tpgrp == -1 && (t->t_dflg&FINT)) {
244 (void) signal(SIGINT, SIG_IGN);
245 (void) signal(SIGQUIT, SIG_IGN);
247 if (wanttty >= 0 && tpgrp >= 0)
248 (void) setpgid(0, pgrp);
249 if (wanttty > 0) {
250 sigttou = sigblock (
251 sigmask(SIGTTOU) |
252 sigmask(SIGTTIN) |
253 sigmask(SIGTSTP));
254 (void) ioctl(FSHTTY, TIOCSPGRP,
255 (tchar *)&pgrp);
256 sigsetmask (sigttou);
258 if (tpgrp > 0)
259 tpgrp = 0;
260 if (t->t_dflg & FNOHUP)
261 (void) signal(SIGHUP, SIG_IGN);
262 if (t->t_dflg & FNICE)
263 (void) setpriority(PRIO_PROCESS,
264 0, t->t_nice);
268 #endif
269 if (pid != 0) {
271 * It would be better if we could wait for the
272 * whole job when we knew the last process
273 * had been started. Pwait, in fact, does
274 * wait for the whole job anyway, but this test
275 * doesn't really express our intentions.
277 if (didfds==0 && t->t_dflg&FPIN) {
278 (void) close(pipein[0]);
279 unsetfd(pipein[0]);
280 (void) close(pipein[1]);
281 unsetfd(pipein[1]);
283 if ((t->t_dflg & (FPOU|FAND)) == 0)
284 pwait();
285 break;
287 doio(t, pipein, pipeout);
288 if (t->t_dflg & FPOU) {
289 (void) close(pipeout[0]);
290 (void) unsetfd(pipeout[0]);
291 (void) close(pipeout[1]);
292 (void) unsetfd(pipeout[1]);
296 * Perform a builtin function.
297 * If we are not forked, arrange for possible stopping
299 if (bifunc) {
300 func(t, bifunc);
301 if (forked)
302 exitstat();
303 break;
305 if (t->t_dtyp != TPAR) {
306 doexec(t);
307 /*NOTREACHED*/
310 * For () commands must put new 0,1,2 in FSH* and recurse
312 OLDSTD = dcopy(0, FOLDSTD);
313 SHOUT = dcopy(1, FSHOUT);
314 SHDIAG = dcopy(2, FSHDIAG);
315 (void) close(SHIN);
316 (void) unsetfd(SHIN);
317 SHIN = -1;
318 didfds = 0;
319 wanttty = -1;
320 t->t_dspr->t_dflg |= t->t_dflg & FINT;
321 execute(t->t_dspr, wanttty);
322 exitstat();
324 case TFIL:
325 t->t_dcar->t_dflg |= FPOU |
326 (t->t_dflg & (FPIN|FAND|FDIAG|FINT));
327 execute(t->t_dcar, wanttty, pipein, pv);
328 t->t_dcdr->t_dflg |= FPIN |
329 (t->t_dflg & (FPOU|FAND|FPAR|FINT));
330 if (wanttty > 0)
331 wanttty = 0; /* got tty already */
332 execute(t->t_dcdr, wanttty, pv, pipeout);
333 break;
335 case TLST:
336 if (t->t_dcar) {
337 t->t_dcar->t_dflg |= t->t_dflg & FINT;
338 execute(t->t_dcar, wanttty);
340 * In strange case of A&B make a new job after A
342 if (t->t_dcar->t_dflg&FAND && t->t_dcdr &&
343 (t->t_dcdr->t_dflg&FAND) == 0)
344 pendjob();
346 if (t->t_dcdr) {
347 t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
348 execute(t->t_dcdr, wanttty);
350 break;
352 case TOR:
353 case TAND:
354 if (t->t_dcar) {
355 t->t_dcar->t_dflg |= t->t_dflg & FINT;
356 execute(t->t_dcar, wanttty);
357 if ((getn(value(S_status/*"status"*/)) == 0) != (t->t_dtyp == TAND))
358 return;
360 if (t->t_dcdr) {
361 t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
362 execute(t->t_dcdr, wanttty);
364 break;
367 * Fall through for all breaks from switch
369 * If there will be no more executions of this
370 * command, flush all file descriptors.
371 * Places that turn on the FREDO bit are responsible
372 * for doing donefds after the last re-execution
374 if (didfds && !(t->t_dflg & FREDO))
375 donefds();
378 * If glob() was called and arguments list is not yet
379 * free'ed, free them here.
381 if (gargv) {
382 blkfree(gargv);
383 gargv = 0;
384 globcnt = 0;
388 #ifdef VFORK
389 void
390 vffree(void)
392 tchar **v;
394 #ifdef TRACE
395 tprintf("TRACE- vffree()\n");
396 #endif
397 if (v = gargv)
398 gargv = 0, xfree( (tchar *)v);
399 if (v = pargv)
400 pargv = 0, xfree( (tchar *)v);
401 _exit(1);
403 #endif
406 * Perform io redirection.
407 * We may or maynot be forked here.
409 void
410 doio(struct command *t, int *pipein, int *pipeout)
412 tchar *cp, *dp;
413 int flags = t->t_dflg;
414 int fd;
416 #ifdef TRACE
417 tprintf("TRACE- doio()\n");
418 #endif
419 if (didfds || (flags & FREDO))
420 return;
421 if ((flags & FHERE) == 0) { /* FHERE already done */
422 (void) close(0);
423 (void) unsetfd(0);
424 if (cp = t->t_dlef) {
425 dp = Dfix1(cp);
426 cp = globone(dp);
427 xfree(dp);
428 xfree(cp);
429 if (open_(cp, 0) < 0)
430 Perror(cp);
431 } else if (flags & FPIN) {
432 fd = dup(pipein[0]);
433 if (fd != -1)
434 setfd(fd);
435 (void) close(pipein[0]);
436 (void) unsetfd(pipein[0]);
437 (void) close(pipein[1]);
438 (void) unsetfd(pipein[1]);
439 } else if ((flags & FINT) && tpgrp == -1) {
440 (void) close(0); /* no need for unsetfd */
441 (void) open("/dev/null", O_RDONLY); /* no need for setfd */
442 } else {
443 fd = dup(OLDSTD);
444 if (fd != -1)
445 setfd(fd);
448 (void) close(1);
449 (void) unsetfd(1);
450 if (cp = t->t_drit) {
451 dp = Dfix1(cp);
452 cp = globone(dp);
453 xfree(dp);
454 if ((flags & FCAT) && open_(cp, 1) >= 0)
455 (void) lseek(1, (off_t)0, 2);
456 else {
457 if (!(flags & FANY) && adrof(S_noclobber/*"noclobber"*/)) {
458 if (flags & FCAT)
459 Perror(cp);
460 chkclob(cp);
462 if (creat_(cp, 0666) < 0)
463 Perror(cp);
465 xfree(cp);
466 } else if (flags & FPOU) {
467 fd = dup(pipeout[1]);
468 if (fd != -1)
469 setfd (fd);
471 else {
472 fd = dup(SHOUT);
473 if (fd != -1)
474 setfd(fd);
477 (void) close(2);
478 (void) unsetfd(2);
479 if (flags & FDIAG) {
480 fd = dup(1);
481 if (fd != -1)
482 setfd(fd);
484 else {
485 fd = dup(SHDIAG);
486 if (fd != -1)
487 setfd(fd);
489 didfds = 1;
492 void
493 mypipe(int *pv)
496 #ifdef TRACE
497 tprintf("TRACE- mypipe()\n");
498 #endif
499 if (pipe(pv) < 0)
500 goto oops;
501 setfd(pv[0]);
502 setfd(pv[1]);
504 pv[0] = dmove(pv[0], -1);
505 pv[1] = dmove(pv[1], -1);
506 if (pv[0] >= 0 && pv[1] >= 0)
507 return;
508 oops:
509 error("Can't make pipe");
512 void
513 chkclob(tchar *cp)
515 struct stat stb;
516 unsigned short type;
518 #ifdef TRACE
519 tprintf("TRACE- chkclob()\n");
520 #endif
521 if (stat_(cp, &stb) < 0)
522 return;
523 type = stb.st_mode & S_IFMT;
524 if (type == S_IFCHR || type == S_IFIFO)
525 return;
526 error("%t: File exists", cp);