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