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