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