xref: /original-bsd/old/sh/service.c (revision 82ca1924)
1 #ifndef lint
2 static char sccsid[] = "@(#)service.c	4.7 05/08/89";
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 #include	"pathnames.h"
17 
18 
19 PROC VOID	gsort();
20 
21 #define ARGMK	01
22 
23 INT		errno;
24 STRING		sysmsg[];
25 INT		num_sysmsg;
26 
27 /* service routines for `execute' */
28 
29 VOID	initio(iop)
30 	IOPTR		iop;
31 {
32 	REG STRING	ion;
33 	REG INT		iof, fd;
34 
35 	IF iop
36 	THEN	iof=iop->iofile;
37 		ion=mactrim(iop->ioname);
38 		IF *ion ANDF (flags&noexec)==0
39 		THEN	IF iof&IODOC
40 			THEN	subst(chkopen(ion),(fd=tmpfil()));
41 				close(fd); fd=chkopen(tmpout); unlink(tmpout);
42 			ELIF iof&IOMOV
43 			THEN	IF eq(minus,ion)
44 				THEN	fd = -1;
45 					close(iof&IOUFD);
46 				ELIF (fd=stoi(ion))>=USERIO
47 				THEN	failed(ion,badfile);
48 				ELSE	fd=dup(fd);
49 				FI
50 			ELIF (iof&IOPUT)==0
51 			THEN	fd=chkopen(ion);
52 			ELIF flags&rshflg
53 			THEN	failed(ion,restricted);
54 			ELIF iof&IOAPP ANDF (fd=open(ion,1))>=0
55 			THEN	lseek(fd, 0L, 2);
56 			ELSE	fd=create(ion);
57 			FI
58 			IF fd>=0
59 			THEN	rename(fd,iof&IOUFD);
60 			FI
61 		FI
62 		initio(iop->ionxt);
63 	FI
64 }
65 
66 STRING	getpath(s)
67 	STRING		s;
68 {
69 	REG STRING	path;
70 	IF any('/',s)
71 	THEN	IF flags&rshflg
72 		THEN	failed(s, restricted);
73 		ELSE	return(nullstr);
74 		FI
75 	ELIF (path = pathnod.namval)==0
76 	THEN	return(_PATH_DEFPATH);
77 	ELSE	return(cpystak(path));
78 	FI
79 }
80 
81 INT	pathopen(path, name)
82 	REG STRING	path, name;
83 {
84 	REG UFD		f;
85 
86 	REP path=catpath(path,name);
87 	PER (f=open(curstak(),0))<0 ANDF path DONE
88 	return(f);
89 }
90 
91 STRING	catpath(path,name)
92 	REG STRING	path;
93 	STRING		name;
94 {
95 	/* leaves result on top of stack */
96 	REG STRING	scanp = path,
97 			argp = locstak();
98 
99 	WHILE *scanp ANDF *scanp!=COLON DO *argp++ = *scanp++ OD
100 	IF scanp!=path THEN *argp++='/' FI
101 	IF *scanp==COLON THEN scanp++ FI
102 	path=(*scanp ? scanp : 0); scanp=name;
103 	WHILE (*argp++ = *scanp++) DONE
104 	return(path);
105 }
106 
107 LOCAL STRING	xecmsg;
108 LOCAL STRING	*xecenv;
109 
110 VOID	execa(at)
111 	STRING		at[];
112 {
113 	REG STRING	path;
114 	REG STRING	*t = at;
115 
116 	IF (flags&noexec)==0
117 	THEN	xecmsg=notfound; path=getpath(*t);
118 		namscan(exname);
119 		xecenv=setenv();
120 		WHILE path=execs(path,t) DONE
121 		failed(*t,xecmsg);
122 	FI
123 }
124 
125 LOCAL STRING	execs(ap,t)
126 	STRING		ap;
127 	REG STRING	t[];
128 {
129 	REG STRING	p, prefix;
130 
131 	prefix=catpath(ap,t[0]);
132 	trim(p=curstak());
133 
134 	sigchk();
135 	execve(p, &t[0] ,xecenv);
136 	SWITCH errno IN
137 
138 	    case ENOEXEC:
139 		flags=0;
140 		comdiv=0; ioset=0;
141 		clearup(); /* remove open files and for loop junk */
142 		IF input THEN close(input) FI
143 		close(output); output=2;
144 		input=chkopen(p);
145 
146 		/* band aid to get csh... 2/26/79 */
147 		{
148 			char c;
149 			if (!isatty(input)) {
150 				read(input, &c, 1);
151 				if (c == '#')
152 					gocsh(t, p, xecenv);
153 				lseek(input, (long) 0, 0);
154 			}
155 		}
156 
157 		/* set up new args */
158 		setargs(t);
159 		longjmp(subshell,1);
160 
161 	    case ENOMEM:
162 		failed(p,toobig);
163 
164 	    case E2BIG:
165 		failed(p,arglist);
166 
167 	    case ETXTBSY:
168 		failed(p,txtbsy);
169 
170 	    default:
171 		xecmsg=badexec;
172 	    case ENOENT:
173 		return(prefix);
174 	ENDSW
175 }
176 
177 gocsh(t, cp, xecenv)
178 	register char **t, *cp, **xecenv;
179 {
180 	char **newt[1000];
181 	register char **p;
182 	register int i;
183 
184 	for (i = 0; t[i]; i++)
185 		newt[i+1] = t[i];
186 	newt[i+1] = 0;
187 	newt[0] = _PATH_CSHELL;
188 	newt[1] = cp;
189 	execve(_PATH_CSHELL, newt, xecenv);
190 }
191 
192 /* for processes to be waited for */
193 #define MAXP 20
194 LOCAL INT	pwlist[MAXP];
195 LOCAL INT	pwc;
196 
197 postclr()
198 {
199 	REG INT		*pw = pwlist;
200 
201 	WHILE pw <= &pwlist[pwc]
202 	DO *pw++ = 0 OD
203 	pwc=0;
204 }
205 
206 VOID	post(pcsid)
207 	INT		pcsid;
208 {
209 	REG INT		*pw = pwlist;
210 
211 	IF pcsid
212 	THEN	WHILE *pw DO pw++ OD
213 		IF pwc >= MAXP-1
214 		THEN	pw--;
215 		ELSE	pwc++;
216 		FI
217 		*pw = pcsid;
218 	FI
219 }
220 
221 VOID	await(i)
222 	INT		i;
223 {
224 	INT		rc=0, wx=0;
225 	INT		w;
226 	INT		ipwc = pwc;
227 
228 	post(i);
229 	WHILE pwc
230 	DO	REG INT		p;
231 		REG INT		sig;
232 		INT		w_hi;
233 
234 		BEGIN
235 		   REG INT	*pw=pwlist;
236  		   IF setjmp(INTbuf) == 0
237  		   THEN	trapjmp[INTR] = 1; p=wait(&w);
238  		   ELSE	p = -1;
239  		   FI
240  		   trapjmp[INTR] = 0;
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 sig < num_sysmsg ANDF sysmsg[sig]
259 			THEN	IF i!=p ORF (flags&prompt)==0
260 				THEN prp(); prn(p); blank()
261 				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(((ARGPTR)(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