date and time created 91/03/07 20:28:05 by bostic
[unix-history] / usr / src / bin / csh / sem.c
CommitLineData
b79f4fa9
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
094e80ed 3 * All rights reserved. The Berkeley Software License Agreement
b79f4fa9
DF
4 * specifies the terms and conditions for redistribution.
5 */
6
35371dec 7#ifndef lint
21787e35 8static char *sccsid = "@(#)sem.c 5.8 (Berkeley) %G%";
094e80ed 9#endif
e0cb907a
BJ
10
11#include "sh.h"
12#include "sh.proc.h"
21787e35 13#include <sys/file.h>
e0cb907a 14#include <sys/ioctl.h>
85443bfb 15#include "pathnames.h"
e0cb907a
BJ
16
17/*
18 * C shell
19 */
20
85443bfb
MT
21static int nosigchld = 0, osigmask;
22static int onosigchld = 0, oosigmask;
e0cb907a
BJ
23/*VARARGS 1*/
24execute(t, wanttty, pipein, pipeout)
25 register struct command *t;
26 int wanttty, *pipein, *pipeout;
27{
28 bool forked = 0;
29 struct biltins *bifunc;
30 int pid = 0;
31 int pv[2];
32
33 if (t == 0)
34 return;
35 if ((t->t_dflg & FAND) && wanttty > 0)
36 wanttty = 0;
37 switch (t->t_dtyp) {
38
39 case TCOM:
40 if ((t->t_dcom[0][0] & (QUOTE|TRIM)) == QUOTE)
35371dec 41 (void) strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
e0cb907a
BJ
42 if ((t->t_dflg & FREDO) == 0)
43 Dfix(t); /* $ " ' \ */
44 if (t->t_dcom[0] == 0)
45 return;
46 /* fall into... */
47
48 case TPAR:
49 if (t->t_dflg & FPOU)
50 mypipe(pipeout);
51 /*
52 * Must do << early so parent will know
53 * where input pointer should be.
54 * If noexec then this is all we do.
55 */
56 if (t->t_dflg & FHERE) {
35371dec 57 (void) close(0);
e0cb907a
BJ
58 heredoc(t->t_dlef);
59 if (noexec)
35371dec 60 (void) close(0);
e0cb907a
BJ
61 }
62 if (noexec)
63 break;
64
65 set("status", "0");
66
67 /*
68 * This mess is the necessary kludge to handle the prefix
69 * builtins: nice, nohup, time. These commands can also
70 * be used by themselves, and this is not handled here.
71 * This will also work when loops are parsed.
72 */
73 while (t->t_dtyp == TCOM)
74 if (eq(t->t_dcom[0], "nice"))
75 if (t->t_dcom[1])
76 if (any(t->t_dcom[1][0], "+-"))
77 if (t->t_dcom[2]) {
78 setname("nice");
79 t->t_nice = getn(t->t_dcom[1]);
80 lshift(t->t_dcom, 2);
81 t->t_dflg |= FNICE;
82 } else
83 break;
84 else {
85 t->t_nice = 4;
86 lshift(t->t_dcom, 1);
87 t->t_dflg |= FNICE;
88 }
89 else
90 break;
91 else if (eq(t->t_dcom[0], "nohup"))
92 if (t->t_dcom[1]) {
93 t->t_dflg |= FNOHUP;
94 lshift(t->t_dcom, 1);
95 } else
96 break;
97 else if (eq(t->t_dcom[0], "time"))
98 if (t->t_dcom[1]) {
99 t->t_dflg |= FTIME;
100 lshift(t->t_dcom, 1);
101 } else
102 break;
103 else
104 break;
105 /*
106 * Check if we have a builtin function and remember which one.
107 */
108 bifunc = t->t_dtyp == TCOM ? isbfunc(t) : (struct biltins *) 0;
109
110 /*
111 * We fork only if we are timed, or are not the end of
112 * a parenthesized list and not a simple builtin function.
113 * Simple meaning one that is not pipedout, niced, nohupped,
114 * or &'d.
115 * It would be nice(?) to not fork in some of these cases.
116 */
117 if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 &&
118 (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP))))
119#ifdef VFORK
120 if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) || bifunc)
121#endif
85443bfb
MT
122 { forked++;
123 if (wanttty >= 0 && !nosigchld) {
85443bfb
MT
124 osigmask = sigblock(sigmask(SIGCHLD));
125 nosigchld = 1;
126 }
127
128 pid = pfork(t, wanttty);
129 if (pid == 0 && nosigchld) {
85443bfb
MT
130 sigsetmask(osigmask);
131 nosigchld = 0;
132 }
133 }
e0cb907a
BJ
134#ifdef VFORK
135 else {
85443bfb 136 sig_t vffree;
35371dec 137 int ochild, osetintr, ohaderr, odidfds;
e0cb907a 138 int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp;
1f7b623f 139 long omask;
e0cb907a 140
e9c261bb
JL
141 /*
142 * Prepare for the vfork by saving everything
143 * that the child corrupts before it exec's.
144 * Note that in some signal implementations
145 * which keep the signal info in user space
146 * (e.g. Sun's) it will also be necessary to
147 * save and restore the current sigvec's for
148 * the signals the child touches before it
149 * exec's.
150 */
85443bfb 151 if (wanttty >= 0 && !nosigchld && !noexec) {
85443bfb
MT
152 osigmask = sigblock(sigmask(SIGCHLD));
153 nosigchld = 1;
154 }
d33af40e 155 omask = sigblock(sigmask(SIGCHLD));
e0cb907a 156 ochild = child; osetintr = setintr;
35371dec 157 ohaderr = haderr; odidfds = didfds;
e0cb907a
BJ
158 oSHIN = SHIN; oSHOUT = SHOUT;
159 oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp;
85443bfb 160 oosigmask = osigmask; onosigchld = nosigchld;
e0cb907a
BJ
161 Vsav = Vdp = 0; Vav = 0;
162 pid = vfork();
163 if (pid < 0) {
35371dec 164 (void) sigsetmask(omask);
e0cb907a
BJ
165 error("No more processes");
166 }
167 forked++;
e9c261bb 168 if (pid) { /* parent */
e0cb907a
BJ
169 child = ochild; setintr = osetintr;
170 haderr = ohaderr; didfds = odidfds;
35371dec 171 SHIN = oSHIN;
e0cb907a
BJ
172 SHOUT = oSHOUT; SHDIAG = oSHDIAG;
173 OLDSTD = oOLDSTD; tpgrp = otpgrp;
85443bfb 174 osigmask = oosigmask; nosigchld = onosigchld;
e0cb907a
BJ
175 xfree(Vsav); Vsav = 0;
176 xfree(Vdp); Vdp = 0;
35371dec 177 xfree((char *)Vav); Vav = 0;
e0cb907a
BJ
178 /* this is from pfork() */
179 palloc(pid, t);
35371dec 180 (void) sigsetmask(omask);
e9c261bb 181 } else { /* child */
e0cb907a
BJ
182 /* this is from pfork() */
183 int pgrp;
184 bool ignint = 0;
185
85443bfb 186 if (nosigchld) {
85443bfb
MT
187 sigsetmask(osigmask);
188 nosigchld = 0;
189 }
e0cb907a
BJ
190 if (setintr)
191 ignint =
192 (tpgrp == -1 && (t->t_dflg&FINT))
193 || gointr && eq(gointr, "-");
194 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
195 child++;
196 if (setintr) {
197 setintr = 0;
ec1a81af 198#ifdef notdef
35371dec 199 (void) signal(SIGCHLD, SIG_DFL);
ec1a81af 200#endif
35371dec 201 (void) signal(SIGINT, ignint ?
d33af40e 202 SIG_IGN : vffree);
35371dec 203 (void) signal(SIGQUIT, ignint ?
d33af40e 204 SIG_IGN : SIG_DFL);
e0cb907a 205 if (wanttty >= 0) {
35371dec
EW
206 (void) signal(SIGTSTP, SIG_DFL);
207 (void) signal(SIGTTIN, SIG_DFL);
208 (void) signal(SIGTTOU, SIG_DFL);
e0cb907a 209 }
35371dec 210 (void) signal(SIGTERM, parterm);
e0cb907a 211 } else if (tpgrp == -1 && (t->t_dflg&FINT)) {
35371dec
EW
212 (void) signal(SIGINT, SIG_IGN);
213 (void) signal(SIGQUIT, SIG_IGN);
e0cb907a 214 }
85443bfb
MT
215 if (wanttty >= 0 && tpgrp >= 0)
216 (void) setpgrp(0, pgrp);
e0cb907a 217 if (wanttty > 0)
35371dec
EW
218 (void) ioctl(FSHTTY, TIOCSPGRP,
219 (char *)&pgrp);
e0cb907a
BJ
220 if (tpgrp > 0)
221 tpgrp = 0;
222 if (t->t_dflg & FNOHUP)
35371dec 223 (void) signal(SIGHUP, SIG_IGN);
e0cb907a 224 if (t->t_dflg & FNICE)
e9c261bb
JL
225 (void) setpriority(PRIO_PROCESS,
226 0, t->t_nice);
e0cb907a
BJ
227 }
228
d33af40e 229 }
e0cb907a
BJ
230#endif
231 if (pid != 0) {
232 /*
233 * It would be better if we could wait for the
234 * whole job when we knew the last process
235 * had been started. Pwait, in fact, does
236 * wait for the whole job anyway, but this test
237 * doesn't really express our intentions.
238 */
35371dec
EW
239 if (didfds==0 && t->t_dflg&FPIN) {
240 (void) close(pipein[0]);
241 (void) close(pipein[1]);
242 }
85443bfb 243 if ((t->t_dflg & FPOU) == 0) {
85443bfb
MT
244 if (nosigchld) {
245#ifdef foobarbaz
246 printf("DID\n");
247#endif
248 sigsetmask(osigmask);
249 nosigchld = 0;
250 }
251 if ((t->t_dflg & FAND) == 0)
252 pwait();
253 }
e0cb907a
BJ
254 break;
255 }
256 doio(t, pipein, pipeout);
35371dec
EW
257 if (t->t_dflg & FPOU) {
258 (void) close(pipeout[0]);
259 (void) close(pipeout[1]);
260 }
e0cb907a
BJ
261
262 /*
263 * Perform a builtin function.
264 * If we are not forked, arrange for possible stopping
265 */
266 if (bifunc) {
267 func(t, bifunc);
268 if (forked)
269 exitstat();
270 break;
271 }
272 if (t->t_dtyp != TPAR) {
273 doexec(t);
274 /*NOTREACHED*/
275 }
276 /*
277 * For () commands must put new 0,1,2 in FSH* and recurse
278 */
279 OLDSTD = dcopy(0, FOLDSTD);
280 SHOUT = dcopy(1, FSHOUT);
281 SHDIAG = dcopy(2, FSHDIAG);
35371dec
EW
282 (void) close(SHIN);
283 SHIN = -1;
284 didfds = 0;
e0cb907a
BJ
285 wanttty = -1;
286 t->t_dspr->t_dflg |= t->t_dflg & FINT;
287 execute(t->t_dspr, wanttty);
288 exitstat();
289
290 case TFIL:
291 t->t_dcar->t_dflg |= FPOU |
292 (t->t_dflg & (FPIN|FAND|FDIAG|FINT));
293 execute(t->t_dcar, wanttty, pipein, pv);
294 t->t_dcdr->t_dflg |= FPIN |
295 (t->t_dflg & (FPOU|FAND|FPAR|FINT));
296 if (wanttty > 0)
297 wanttty = 0; /* got tty already */
298 execute(t->t_dcdr, wanttty, pv, pipeout);
299 break;
300
301 case TLST:
302 if (t->t_dcar) {
303 t->t_dcar->t_dflg |= t->t_dflg & FINT;
304 execute(t->t_dcar, wanttty);
305 /*
306 * In strange case of A&B make a new job after A
307 */
308 if (t->t_dcar->t_dflg&FAND && t->t_dcdr &&
309 (t->t_dcdr->t_dflg&FAND) == 0)
310 pendjob();
311 }
312 if (t->t_dcdr) {
313 t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
314 execute(t->t_dcdr, wanttty);
315 }
316 break;
317
318 case TOR:
319 case TAND:
320 if (t->t_dcar) {
321 t->t_dcar->t_dflg |= t->t_dflg & FINT;
322 execute(t->t_dcar, wanttty);
323 if ((getn(value("status")) == 0) != (t->t_dtyp == TAND))
324 return;
325 }
326 if (t->t_dcdr) {
327 t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
328 execute(t->t_dcdr, wanttty);
329 }
330 break;
331 }
332 /*
333 * Fall through for all breaks from switch
334 *
335 * If there will be no more executions of this
336 * command, flush all file descriptors.
337 * Places that turn on the FREDO bit are responsible
338 * for doing donefds after the last re-execution
339 */
340 if (didfds && !(t->t_dflg & FREDO))
341 donefds();
342}
343
344#ifdef VFORK
345vffree()
346{
347 register char **v;
348
349 if (v = gargv)
35371dec 350 gargv = 0, xfree((char *)v);
e0cb907a 351 if (v = pargv)
35371dec 352 pargv = 0, xfree((char *)v);
e0cb907a
BJ
353 _exit(1);
354}
355#endif
356
357/*
358 * Perform io redirection.
359 * We may or maynot be forked here.
360 */
361doio(t, pipein, pipeout)
362 register struct command *t;
363 int *pipein, *pipeout;
364{
365 register char *cp;
366 register int flags = t->t_dflg;
367
368 if (didfds || (flags & FREDO))
369 return;
370 if ((flags & FHERE) == 0) { /* FHERE already done */
35371dec 371 (void) close(0);
e0cb907a
BJ
372 if (cp = t->t_dlef) {
373 cp = globone(Dfix1(cp));
374 xfree(cp);
375 if (open(cp, 0) < 0)
376 Perror(cp);
35371dec
EW
377 } else if (flags & FPIN) {
378 (void) dup(pipein[0]);
379 (void) close(pipein[0]);
380 (void) close(pipein[1]);
381 } else if ((flags & FINT) && tpgrp == -1) {
382 (void) close(0);
85443bfb 383 (void) open(_PATH_DEVNULL, 0);
35371dec 384 } else
d671c35e 385 (void) dup(OLDSTD);
e0cb907a 386 }
35371dec 387 (void) close(1);
e0cb907a
BJ
388 if (cp = t->t_drit) {
389 cp = globone(Dfix1(cp));
390 xfree(cp);
21787e35 391 if (!(flags & FCAT) || open(cp, O_WRONLY|O_APPEND, 0) < 0) {
e0cb907a
BJ
392 if (!(flags & FANY) && adrof("noclobber")) {
393 if (flags & FCAT)
394 Perror(cp);
395 chkclob(cp);
396 }
397 if (creat(cp, 0666) < 0)
398 Perror(cp);
399 }
400 } else if (flags & FPOU)
35371dec 401 (void) dup(pipeout[1]);
e0cb907a 402 else
d671c35e 403 (void) dup(SHOUT);
e0cb907a 404
35371dec
EW
405 (void) close(2);
406 if (flags & FDIAG)
407 (void) dup(1);
408 else
d671c35e 409 (void) dup(SHDIAG);
e0cb907a
BJ
410 didfds = 1;
411}
412
413mypipe(pv)
414 register int *pv;
415{
416
417 if (pipe(pv) < 0)
418 goto oops;
419 pv[0] = dmove(pv[0], -1);
420 pv[1] = dmove(pv[1], -1);
421 if (pv[0] >= 0 && pv[1] >= 0)
422 return;
423oops:
424 error("Can't make pipe");
425}
426
427chkclob(cp)
428 register char *cp;
429{
430 struct stat stb;
431
432 if (stat(cp, &stb) < 0)
433 return;
434 if ((stb.st_mode & S_IFMT) == S_IFCHR)
435 return;
436 error("%s: File exists", cp);
437}