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