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