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