1 #
2 /*
3 * UNIX shell
4 *
5 * S. R. Bourne
6 * Bell Telephone Laboratories
7 *
8 */
9
10 #include "defs.h"
11
12
13
14 #define ARGMK 01
15
16 LOCAL CSTRING execs(CSTRING, STRING *);
17 LOCAL VOID gsort(STRING *, STRING *);
18 LOCAL INT split(STRING);
19 #if defined(GOCSH) /* RENO */
20 LOCAL VOID gocsh(STRING *, STRING, STRING *);
21 #endif
22
23
24 /* service routines for `execute' */
25
initio(iop)26 VOID initio(iop)
27 IOPTR iop;
28 {
29 REG STRING ion;
30 REG INT iof, fd=-1; /* GCC */
31
32 IF iop
33 THEN iof=iop->iofile;
34 ion=mactrim(iop->ioname);
35 IF *ion ANDF (flags&noexec)==0
36 THEN IF iof&IODOC
37 THEN subst(chkopen(ion),(fd=tmpfil()));
38 close(fd); fd=chkopen(tmpout); unlink(tmpout);
39 ELIF iof&IOMOV
40 THEN IF eq(minus,ion)
41 THEN fd = -1;
42 close(iof&IOUFD);
43 ELIF (fd=stoi(ion))>=USERIO
44 THEN failed(ion,badfile);
45 /*NOTREACHED*/
46 ELSE fd=dup(fd);
47 FI
48 ELIF (iof&IOPUT)==0
49 THEN fd=chkopen(ion);
50 ELIF flags&rshflg
51 THEN failed(ion,restricted);
52 /*NOTREACHED*/
53 #if defined(RENO)
54 ELIF (iof&IOAPP)==0 ORF
55 (fd=open(ion,O_WRONLY|O_APPEND))<0
56 THEN fd=create(ion);
57 #else /* V7 */
58 ELIF iof&IOAPP ANDF (fd=open(ion,O_WRONLY))>=0
59 THEN lseek(fd, (OFFSET) 0, SEEK_END);
60 ELSE fd=create(ion);
61 #endif
62 FI
63 IF fd>=0
64 THEN rename(fd,iof&IOUFD);
65 FI
66 FI
67 initio(iop->ionxt);
68 FI
69 }
70
getpath(s)71 CSTRING getpath(s)
72 CSTRING s;
73 {
74 REG CSTRING path;
75
76 #if defined(SYSIII)
77 IF any('/',s) ORF any(('/'|QUOTE),s)
78 #else /* V7 */
79 IF any('/',s)
80 #endif
81 THEN IF flags&rshflg
82 THEN failed(s, restricted);
83 /*NOTREACHED*/
84 FI
85 ELIF (path = pathnod.namval)==0
86 THEN return(defpath);
87 ELSE return(cpystak(path));
88 FI
89 return(nullstr);
90 }
91
pathopen(path,name)92 INT pathopen(path, name)
93 REG CSTRING path, name;
94 {
95 REG UFD f;
96
97 REP path=catpath(path,name);
98 PER (f=open(curstak(),O_RDONLY))<0 ANDF path DONE
99 return(f);
100 }
101
catpath(path,name)102 CSTRING catpath(path,name)
103 REG CSTRING path;
104 CSTRING name;
105 {
106 /* leaves result on top of stack */
107 REG CSTRING scanp = path;
108 REG STRING argp = locstak();
109
110 WHILE *scanp ANDF *scanp!=COLON DO *argp++ = *scanp++ OD
111 IF scanp!=path THEN *argp++='/' FI
112 IF *scanp==COLON THEN scanp++ FI
113 path=(*scanp ? scanp : 0); scanp=name;
114 WHILE (*argp++ = *scanp++) DONE
115 return(path);
116 }
117
118 LOCAL CSTRING xecmsg;
119 LOCAL STRING *xecenv;
120
execa(at)121 VOID execa(at)
122 STRING at[];
123 {
124 REG CSTRING path;
125 REG STRING *t = at;
126
127 IF (flags&noexec)==0
128 THEN xecmsg=notfound; path=getpath(*t);
129 namscan(exname);
130 xecenv=setenv();
131 WHILE (path=execs(path,t))!=NIL DONE /* GCC */
132 failed(*t,xecmsg);
133 /*NOTREACHED*/
134 FI
135 }
136
137
execs(ap,t)138 LOCAL CSTRING execs(ap,t)
139 CSTRING ap;
140 REG STRING t[];
141 {
142 REG STRING p;
143 REG CSTRING prefix;
144
145 prefix=catpath(ap,t[0]);
146 trim(p=curstak());
147
148 sigchk();
149 execve(p, &t[0] ,xecenv);
150 SWITCH errno IN
151
152 case ENOEXEC:
153 flags=0;
154 comdiv=0; ioset=0;
155 clearup(); /* remove open files and for loop junk */
156 IF input THEN close(input) FI
157 close(output); output=2;
158 input=chkopen(p);
159
160 #if defined(GOCSH) /* RENO */
161 /* band aid to get csh... 2/26/79 */
162 BEGIN
163 CHAR c;
164
165 IF !isatty(input)
166 THEN read(input, &c, 1);
167 IF c == '#' THEN gocsh(t, p, xecenv) FI
168 lseek(input, (OFFSET) 0, SEEK_SET);
169 FI
170 END
171 #endif
172
173 /* set up new args */
174 setargs(t);
175 longjmp(subshell,1);
176 /*NOTREACHED*/
177
178 case ENOMEM:
179 failed(p,toobig);
180 /*NOTREACHED*/
181
182 case E2BIG:
183 failed(p,arglist);
184 /*NOTREACHED*/
185
186 case ETXTBSY:
187 failed(p,txtbsy);
188 /*NOTREACHED*/
189
190 default:
191 xecmsg=badexec;
192 /*FALLTHROUGH*/
193
194 case ENOENT:
195 return(prefix);
196 ENDSW
197 }
198
199 #if defined(GOCSH) /* RENO */
gocsh(t,cp,xecenv)200 LOCAL VOID gocsh(t, cp, xecenv)
201 REG STRING *t, cp, *xecenv;
202 {
203 STRING *newt[1000];
204 REG STRING *p;
205 REG INT i;
206
207 FOR i = 0; t[i]; i++ DO newt[i+1] = t[i] OD
208 newt[i+1] = 0;
209 newt[0] = _PATH_CSHELL;
210 newt[1] = cp;
211 execve(_PATH_CSHELL, newt, xecenv);
212 }
213 #endif
214
215 /* for processes to be waited for */
216 #define MAXP 20
217 LOCAL INT pwlist[MAXP];
218 LOCAL INT pwc;
219
postclr()220 VOID postclr()
221 {
222 REG INT *pw = pwlist;
223
224 WHILE pw <= &pwlist[pwc]
225 DO *pw++ = 0 OD
226 pwc=0;
227 }
228
post(pcsid)229 VOID post(pcsid)
230 INT pcsid;
231 {
232 REG INT *pw = pwlist;
233
234 IF pcsid
235 THEN WHILE *pw DO pw++ OD
236 IF pwc >= MAXP-1
237 THEN pw--;
238 ELSE pwc++;
239 FI
240 *pw = pcsid;
241 FI
242 }
243
244 #if defined(SYSIII)
await(i,bckg)245 VOID await(i, bckg)
246 INT i, bckg;
247 #else /* V7 */
248 VOID await(i)
249 INT i;
250 #endif
251 {
252 INT rc=0, wx=0;
253 INT w;
254 INT ipwc = pwc;
255
256 post(i);
257 WHILE pwc
258 DO REG INT p;
259 REG INT sig;
260 INT w_hi;
261 #if defined(SYSIII)
262 INT found = 0;
263 #endif
264
265 BEGIN
266 REG INT *pw=pwlist;
267 #if defined(RENO)
268 IF setjmp(INTbuf) == 0
269 THEN trapjmp[INTR] = 1;
270 #endif
271 p=wait(&w);
272 #if defined(SYSIII)
273 IF wasintr THEN
274 wasintr = 0;
275 IF bckg THEN break; FI
276 FI
277 #endif
278 #if defined(RENO)
279 ELSE p = -1;
280 FI
281 trapjmp[INTR] = 0;
282 #endif
283 WHILE pw <= &pwlist[ipwc]
284 DO IF *pw==p
285 THEN *pw=0; pwc--;
286 #if defined(SYSIII)
287 found++;
288 #endif
289 ELSE pw++;
290 FI
291 OD
292 END
293
294 #if defined(SYSIII)
295 IF p == -1
296 THEN IF bckg THEN
297 REG INT *pw =pwlist;
298 WHILE pw <= &pwlist[ipwc] ANDF i != *pw
299 DO pw++; OD
300 IF i == *pw THEN *pw = 0; pwc-- FI
301 FI
302 continue
303 FI
304 #else /* V7 */
305 IF p == -1 THEN continue FI
306 #endif
307
308 w_hi = (w>>8)&LOBYTE;
309
310 IF (sig = w&0177)!=0 /* GCC */
311 THEN IF sig == 0177 /* ptrace! return */
312 THEN prs("ptrace: ");
313 sig = w_hi;
314 FI
315 #if defined(RENO)
316 IF sig < num_sysmsg ANDF sysmsg[sig]
317 #else /* V7 */
318 IF sysmsg[sig]
319 #endif
320 THEN IF i!=p ORF (flags&prompt)==0 THEN prp(); prn(p); blank() FI
321 prs(sysmsg[sig]);
322 IF w&0200 THEN prs(coredump) FI
323 FI
324 newline();
325 FI
326
327 #if defined(SYSIII)
328 IF rc==0 ANDF found != 0
329 #else /* V7 */
330 IF rc==0
331 #endif
332 THEN rc = (sig ? sig|SIGFLG : w_hi);
333 FI
334 wx |= w;
335 #if defined(SYSIII)
336 IF p == i THEN break FI
337 #endif
338 OD
339
340 IF wx ANDF flags&errflg
341 THEN exitsh(rc);
342 /*NOTREACHED*/
343 FI
344 exitval=rc; exitset();
345 }
346
trim(at)347 VOID trim(at)
348 STRING at;
349 {
350 REG STRING p;
351 REG INT c;
352 REG INT q=0;
353
354 IF (p=at)!=NIL /* GCC */
355 THEN WHILE (c = *p)!=0 /* GCC */
356 DO *p++=c&STRIP; q |= c OD
357 FI
358 nosubst=q"E;
359 }
360
mactrim(s)361 STRING mactrim(s)
362 STRING s;
363 {
364 REG STRING t=macro(s);
365 trim(t);
366 return(t);
367 }
368
scan(argn)369 STRING *scan(argn)
370 INT argn;
371 {
372 REG ARGPTR argp = (ARGPTR) (Rcheat(gchain)&~ARGMK);
373 REG STRING *comargn, *comargm;
374
375 comargn=(STRING *) getstak(BYTESPERWORD*argn+BYTESPERWORD);
376 comargm = comargn += argn; *comargn = ENDARGS;
377
378 WHILE argp
379 DO *--comargn = argp->argval;
380 IF (argp = argp->argnxt)!=NIL /* GCC */
381 THEN trim(*comargn);
382 FI
383 IF argp==0 ORF Rcheat(argp)&ARGMK
384 THEN gsort(comargn,comargm);
385 comargm = comargn;
386 FI
387 /* Lcheat(argp) &= ~ARGMK; */
388 argp = (ARGPTR) (Rcheat(argp)&~ARGMK);
389 OD
390 return(comargn);
391 }
392
gsort(from,to)393 LOCAL VOID gsort(from,to)
394 STRING from[], to[];
395 {
396 INT k, m, n;
397 REG INT i, j;
398
399 IF (n=to-from)<=1 THEN return FI
400
401 FOR j=1; j<=n; j*=2 DONE
402
403 FOR m=2*j-1; m/=2;
404 DO k=n-m;
405 FOR j=0; j<k; j++
406 DO FOR i=j; i>=0; i-=m
407 DO REG STRING *fromi; fromi = &from[i];
408 IF cf(fromi[m],fromi[0])>0
409 THEN break;
410 ELSE STRING s; s=fromi[m]; fromi[m]=fromi[0]; fromi[0]=s;
411 FI
412 OD
413 OD
414 OD
415 }
416
417 /* Argument list generation */
418
getarg(ac)419 INT getarg(ac)
420 COMPTR ac;
421 {
422 REG ARGPTR argp;
423 REG INT count=0;
424 REG COMPTR c;
425
426 IF (c=ac)!=NIL /* GCC */
427 THEN argp=c->comarg;
428 WHILE argp
429 DO count += split(macro(argp->argval));
430 argp=argp->argnxt;
431 OD
432 FI
433 return(count);
434 }
435
split(s)436 LOCAL INT split(s)
437 /* blank interpretation routine */
438 REG STRING s;
439 {
440 REG STRING argp;
441 REG INT c;
442 INT count=0;
443
444 LOOP sigchk(); argp=(STRING) (locstak()+BYTESPERWORD);
445 WHILE (c = *s++, !any(c,ifsnod.namval) && c)
446 DO *argp++ = c OD
447 IF argp==(STRING)(staktop+BYTESPERWORD)
448 THEN IF c
449 THEN continue;
450 ELSE return(count);
451 FI
452 ELIF c==0
453 THEN s--;
454 FI
455 /* file name generation */
456 IF (c=expand(((ARGPTR) (argp=(STRING) endstak(argp)))->argval,0))!=0 /* GCC */
457 THEN count += c;
458 ELSE /* assign(&fngnod, argp->argval); */
459 makearg((ARGPTR) argp); count++;
460 FI
461 Lcheat(gchain) |= ARGMK;
462 POOL
463 }
464
465 #if defined(SYSIII)
simple(s)466 CSTRING simple(s)
467 CSTRING s;
468 {
469 CSTRING sname=s;
470
471 LOOP
472 IF any('/', sname)
473 THEN WHILE *sname++ != '/' DONE
474 ELSE return(sname);
475 FI
476 POOL
477 }
478 #endif
479