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