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&QUOTE;
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