xref: /illumos-gate/usr/src/cmd/sh/service.c (revision cd61ae21816e53b94bc1673f3f1aa651fc3115e8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 /*
30  * UNIX shell
31  */
32 
33 #include	"defs.h"
34 #include	<errno.h>
35 #include	<fcntl.h>
36 
37 #define	ARGMK	01
38 
39 static unsigned char	*execs();
40 static void	gsort();
41 static int	split();
42 extern void makearg(struct argnod *);
43 extern short topfd;
44 
45 
46 /*
47  * service routines for `execute'
48  */
49 short
50 initio(struct ionod *iop, int save)
51 {
52 	unsigned char	*ion;
53 	int	iof, fd;
54 	int		ioufd;
55 	short	lastfd;
56 	int	newmode;
57 
58 	lastfd = topfd;
59 	while (iop) {
60 		iof = iop->iofile;
61 		ion = mactrim(iop->ioname);
62 		ioufd = iof & IOUFD;
63 
64 		if (*ion && (flags&noexec) == 0) {
65 			if (save) {
66 				fdmap[topfd].org_fd = ioufd;
67 				fdmap[topfd++].dup_fd = savefd(ioufd);
68 			}
69 
70 			if (iof & IODOC_SUBST) {
71 				struct tempblk tb;
72 
73 				subst(chkopen(ion, 0), (fd = tmpfil(&tb)));
74 
75 				/*
76 				 * pushed in tmpfil() --
77 				 * bug fix for problem with
78 				 * in-line scripts
79 				 */
80 				poptemp();
81 
82 				fd = chkopen(tmpout, 0);
83 				unlink((const char *)tmpout);
84 			} else if (iof & IOMOV) {
85 				if (eq(minus, ion)) {
86 					fd = -1;
87 					close(ioufd);
88 				} else if ((fd = stoi(ion)) >= USERIO) {
89 					failed(ion, badfile);
90 				}
91 				else
92 					fd = dup(fd);
93 			} else if (((iof & IOPUT) == 0) && ((iof & IORDW) == 0))
94 				fd = chkopen(ion, 0);
95 			else if (iof & IORDW) /* For <> */ {
96 				newmode = O_RDWR|O_CREAT;
97 				fd = chkopen(ion, newmode);
98 			} else if (flags & rshflg) {
99 				failed(ion, restricted);
100 			} else if (iof & IOAPP &&
101 			    (fd = open((char *)ion, 1)) >= 0) {
102 				lseek(fd, (off_t)0, SEEK_END);
103 			} else {
104 				fd = create(ion);
105 			}
106 			if (fd >= 0)
107 				renamef(fd, ioufd);
108 		}
109 
110 		iop = iop->ionxt;
111 	}
112 	return (lastfd);
113 }
114 
115 unsigned char *
116 simple(s)
117 unsigned char	*s;
118 {
119 	unsigned char	*sname;
120 
121 	sname = s;
122 	while (1) {
123 		if (any('/', sname))
124 			while (*sname++ != '/')
125 				;
126 		else
127 			return (sname);
128 	}
129 }
130 
131 unsigned char *
132 getpath(s)
133 	unsigned char	*s;
134 {
135 	unsigned char	*path, *newpath;
136 	int pathlen;
137 
138 	if (any('/', s))
139 	{
140 		if (flags & rshflg)
141 			failed(s, restricted);
142 		else
143 			return ((unsigned char *)nullstr);
144 	} else if ((path = pathnod.namval) == 0)
145 		return ((unsigned char *)defpath);
146 	else {
147 		pathlen = length(path)-1;
148 		/* Add extra ':' if PATH variable ends in ':' */
149 		if (pathlen > 2 && path[pathlen - 1] == ':' &&
150 				path[pathlen - 2] != ':') {
151 			newpath = locstak();
152 			(void) memcpystak(newpath, path, pathlen);
153 			newpath[pathlen] = ':';
154 			endstak(newpath + pathlen + 1);
155 			return (newpath);
156 		} else
157 			return (cpystak(path));
158 	}
159 }
160 
161 int
162 pathopen(unsigned char *path, unsigned char *name)
163 {
164 	int	f;
165 
166 	do
167 	{
168 		path = catpath(path, name);
169 	} while ((f = open((char *)curstak(), 0)) < 0 && path);
170 	return (f);
171 }
172 
173 unsigned char *
174 catpath(unsigned char *path, unsigned char *name)
175 {
176 	/*
177 	 * leaves result on top of stack
178 	 */
179 	unsigned char	*scanp = path;
180 	unsigned char	*argp = locstak();
181 
182 	while (*scanp && *scanp != COLON) {
183 		if (argp >= brkend)
184 			growstak(argp);
185 		*argp++ = *scanp++;
186 	}
187 	if (scanp != path) {
188 		if (argp >= brkend)
189 			growstak(argp);
190 		*argp++ = '/';
191 	}
192 	if (*scanp == COLON)
193 		scanp++;
194 	path = (*scanp ? scanp : 0);
195 	scanp = name;
196 	do
197 	{
198 		if (argp >= brkend)
199 			growstak(argp);
200 	}
201 	while (*argp++ = *scanp++)
202 		;
203 	return (path);
204 }
205 
206 unsigned char *
207 nextpath(unsigned char *path)
208 {
209 	unsigned char	*scanp = path;
210 
211 	while (*scanp && *scanp != COLON)
212 		scanp++;
213 
214 	if (*scanp == COLON)
215 		scanp++;
216 
217 	return (*scanp ? scanp : 0);
218 }
219 
220 static const char	*xecmsg;
221 static unsigned char	**xecenv;
222 
223 void
224 execa(unsigned char *at[], short pos)
225 {
226 	unsigned char	*path;
227 	unsigned char	**t = at;
228 	int		cnt;
229 
230 	if ((flags & noexec) == 0) {
231 		xecmsg = notfound;
232 		path = getpath(*t);
233 		xecenv = local_setenv();
234 
235 		if (pos > 0) {
236 			cnt = 1;
237 			while (cnt != pos) {
238 				++cnt;
239 				path = nextpath(path);
240 			}
241 			execs(path, t);
242 			path = getpath(*t);
243 		}
244 		while (path = execs(path, t))
245 			;
246 		failed(*t, xecmsg);
247 	}
248 }
249 
250 static unsigned char *
251 execs(unsigned char *ap, unsigned char *t[])
252 {
253 	unsigned char	*p, *prefix;
254 	unsigned char	*savptr;
255 
256 	prefix = catpath(ap, t[0]);
257 	trim(p = curstak());
258 	sigchk();
259 
260 	execve((const char *)p, (char *const *)&t[0],
261 	    (char *const *)xecenv);
262 
263 	switch (errno) {
264 	case ENOEXEC:		/* could be a shell script */
265 		funcnt = 0;
266 		flags = 0;
267 		*flagadr = 0;
268 		comdiv = 0;
269 		ioset = 0;
270 		clearup();	/* remove open files and for loop junk */
271 		if (input)
272 			close(input);
273 		input = chkopen(p, 0);
274 
275 #ifdef ACCT
276 		preacct(p);	/* reset accounting */
277 #endif
278 
279 		/*
280 		 * set up new args
281 		 */
282 
283 		setargs(t);
284 		longjmp(subshell, 1);
285 
286 	case ENOMEM:
287 		failed(p, toobig);
288 
289 	case E2BIG:
290 		failed(p, arglist);
291 
292 	case ETXTBSY:
293 		failed(p, txtbsy);
294 
295 	case ELIBACC:
296 		failed(p, libacc);
297 
298 	case ELIBBAD:
299 		failed(p, libbad);
300 
301 	case ELIBSCN:
302 		failed(p, libscn);
303 
304 	case ELIBMAX:
305 		failed(p, libmax);
306 
307 	default:
308 		xecmsg = badexec;
309 	case ENOENT:
310 		return (prefix);
311 	}
312 }
313 
314 BOOL		nosubst;
315 
316 void
317 trim(unsigned char *at)
318 {
319 	unsigned char	*last;
320 	unsigned char 	*current;
321 	unsigned char	c;
322 	int	len;
323 	wchar_t	wc;
324 
325 	nosubst = 0;
326 	if (current = at) {
327 		last = at;
328 		while (c = *current) {
329 			if ((len = mbtowc(&wc, (char *)current,
330 			    MB_LEN_MAX)) <= 0) {
331 				*last++ = c;
332 				current++;
333 				continue;
334 			}
335 
336 			if (wc != '\\') {
337 				memcpy(last, current, len);
338 				last += len;
339 				current += len;
340 				continue;
341 			}
342 
343 			/* remove \ and quoted nulls */
344 			nosubst = 1;
345 			current++;
346 			if (c = *current) {
347 				if ((len = mbtowc(&wc, (char *)current,
348 				    MB_LEN_MAX)) <= 0) {
349 					*last++ = c;
350 					current++;
351 					continue;
352 				}
353 				memcpy(last, current, len);
354 				last += len;
355 				current += len;
356 			} else
357 				current++;
358 		}
359 
360 		*last = 0;
361 	}
362 }
363 
364 /* Same as trim, but only removes backlashes before slashes */
365 void
366 trims(at)
367 unsigned char	*at;
368 {
369 	unsigned char	*last;
370 	unsigned char 	*current;
371 	unsigned char	c;
372 	int	len;
373 	wchar_t	wc;
374 
375 	if (current = at)
376 	{
377 		last = at;
378 		while (c = *current) {
379 			if ((len = mbtowc(&wc, (char *)current,
380 					MB_LEN_MAX)) <= 0) {
381 				*last++ = c;
382 				current++;
383 				continue;
384 			}
385 
386 			if (wc != '\\') {
387 				memcpy(last, current, len);
388 				last += len; current += len;
389 				continue;
390 			}
391 
392 			/* remove \ and quoted nulls */
393 			current++;
394 			if (!(c = *current)) {
395 				current++;
396 				continue;
397 			}
398 
399 			if (c == '/') {
400 				*last++ = c;
401 				current++;
402 				continue;
403 			}
404 
405 			*last++ = '\\';
406 			if ((len = mbtowc(&wc, (char *)current,
407 					MB_LEN_MAX)) <= 0) {
408 				*last++ = c;
409 				current++;
410 				continue;
411 			}
412 			memcpy(last, current, len);
413 			last += len; current += len;
414 		}
415 		*last = 0;
416 	}
417 }
418 
419 unsigned char *
420 mactrim(s)
421 unsigned char	*s;
422 {
423 	unsigned char	*t = macro(s);
424 
425 	trim(t);
426 	return (t);
427 }
428 
429 unsigned char **
430 scan(argn)
431 int	argn;
432 {
433 	struct argnod *argp =
434 			(struct argnod *)(Rcheat(gchain) & ~ARGMK);
435 	unsigned char **comargn, **comargm;
436 
437 	comargn = (unsigned char **)getstak(BYTESPERWORD * argn + BYTESPERWORD);
438 	comargm = comargn += argn;
439 	*comargn = ENDARGS;
440 	while (argp)
441 	{
442 		*--comargn = argp->argval;
443 
444 		trim(*comargn);
445 		argp = argp->argnxt;
446 
447 		if (argp == 0 || Rcheat(argp) & ARGMK)
448 		{
449 			gsort(comargn, comargm);
450 			comargm = comargn;
451 		}
452 		argp = (struct argnod *)(Rcheat(argp) & ~ARGMK);
453 	}
454 	return (comargn);
455 }
456 
457 static void
458 gsort(from, to)
459 unsigned char	*from[], *to[];
460 {
461 	int	k, m, n;
462 	int	i, j;
463 
464 	if ((n = to - from) <= 1)
465 		return;
466 	for (j = 1; j <= n; j *= 2)
467 		;
468 	for (m = 2 * j - 1; m /= 2; )
469 	{
470 		k = n - m;
471 		for (j = 0; j < k; j++)
472 		{
473 			for (i = j; i >= 0; i -= m)
474 			{
475 				unsigned char **fromi;
476 
477 				fromi = &from[i];
478 				if (cf(fromi[m], fromi[0]) > 0)
479 				{
480 					break;
481 				}
482 				else
483 				{
484 					unsigned char *s;
485 
486 					s = fromi[m];
487 					fromi[m] = fromi[0];
488 					fromi[0] = s;
489 				}
490 			}
491 		}
492 	}
493 }
494 
495 /*
496  * Argument list generation
497  */
498 int
499 getarg(ac)
500 struct comnod	*ac;
501 {
502 	struct argnod	*argp;
503 	int		count = 0;
504 	struct comnod	*c;
505 
506 	if (c = ac)
507 	{
508 		argp = c->comarg;
509 		while (argp)
510 		{
511 			count += split(macro(argp->argval), 1);
512 			argp = argp->argnxt;
513 		}
514 	}
515 	return (count);
516 }
517 
518 static int
519 split(s)		/* blank interpretation routine */
520 unsigned char	*s;
521 {
522 	unsigned char	*argp;
523 	int		c;
524 	int		count = 0;
525 	for (;;)
526 	{
527 		int length;
528 		sigchk();
529 		argp = locstak() + BYTESPERWORD;
530 		while (c = *s) {
531 			wchar_t wc;
532 			if ((length = mbtowc(&wc, (char *)s,
533 					MB_LEN_MAX)) <= 0) {
534 				wc = (unsigned char)*s;
535 				length = 1;
536 			}
537 
538 			if (c == '\\') { /* skip over quoted characters */
539 				if (argp >= brkend)
540 					growstak(argp);
541 				*argp++ = c;
542 				s++;
543 				/* get rest of multibyte character */
544 				if ((length = mbtowc(&wc, (char *)s,
545 						MB_LEN_MAX)) <= 0) {
546 					wc = (unsigned char)*s;
547 					length = 1;
548 				}
549 				if (argp >= brkend)
550 					growstak(argp);
551 				*argp++ = *s++;
552 				while (--length > 0) {
553 					if (argp >= brkend)
554 						growstak(argp);
555 					*argp++ = *s++;
556 				}
557 				continue;
558 			}
559 
560 			if (anys(s, ifsnod.namval)) {
561 				/* skip to next character position */
562 				s += length;
563 				break;
564 			}
565 
566 			if (argp >= brkend)
567 				growstak(argp);
568 			*argp++ = c;
569 			s++;
570 			while (--length > 0) {
571 				if (argp >= brkend)
572 					growstak(argp);
573 				*argp++ = *s++;
574 			}
575 		}
576 		if (argp == staktop + BYTESPERWORD)
577 		{
578 			if (c)
579 			{
580 				continue;
581 			}
582 			else
583 			{
584 				return (count);
585 			}
586 		}
587 		/*
588 		 * file name generation
589 		 */
590 
591 		argp = endstak(argp);
592 		trims(((struct argnod *)argp)->argval);
593 		if ((flags & nofngflg) == 0 &&
594 			(c = expand(((struct argnod *)argp)->argval, 0)))
595 			count += c;
596 		else
597 		{
598 			makearg((struct argnod *)argp);
599 			count++;
600 		}
601 		gchain = (struct argnod *)((int)gchain | ARGMK);
602 	}
603 }
604 
605 #ifdef ACCT
606 #include	<sys/types.h>
607 #include	<sys/acct.h>
608 #include 	<sys/times.h>
609 
610 struct acct sabuf;
611 struct tms buffer;
612 static clock_t before;
613 static int shaccton;	/* 0 implies do not write record on exit */
614 			/* 1 implies write acct record on exit */
615 static comp_t compress(clock_t);
616 
617 
618 /*
619  *	suspend accounting until turned on by preacct()
620  */
621 void
622 suspacct(void)
623 {
624 	shaccton = 0;
625 }
626 
627 void
628 preacct(unsigned char *cmdadr)
629 {
630 	unsigned char *simple();
631 
632 	if (acctnod.namval && *acctnod.namval) {
633 		sabuf.ac_btime = time((time_t *)0);
634 		before = times(&buffer);
635 		sabuf.ac_uid = getuid();
636 		sabuf.ac_gid = getgid();
637 		movstrn(simple(cmdadr), sabuf.ac_comm, sizeof (sabuf.ac_comm));
638 		shaccton = 1;
639 	}
640 }
641 
642 void
643 doacct(void)
644 {
645 	int fd;
646 	clock_t after;
647 
648 	if (shaccton) {
649 		after = times(&buffer);
650 		sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime);
651 		sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime);
652 		sabuf.ac_etime = compress(after - before);
653 
654 		if ((fd = open((char *)acctnod.namval,
655 		    O_WRONLY | O_APPEND | O_CREAT, 0666)) != -1) {
656 			write(fd, &sabuf, sizeof (sabuf));
657 			close(fd);
658 		}
659 	}
660 }
661 
662 /*
663  *	Produce a pseudo-floating point representation
664  *	with 3 bits base-8 exponent, 13 bits fraction
665  */
666 
667 static comp_t
668 compress(clock_t t)
669 {
670 	int exp = 0;
671 	int rund = 0;
672 
673 	while (t >= 8192) {
674 		exp++;
675 		rund = t & 04;
676 		t >>= 3;
677 	}
678 
679 	if (rund) {
680 		t++;
681 		if (t >= 8192) {
682 			t >>= 3;
683 			exp++;
684 		}
685 	}
686 	return ((exp << 13) + t);
687 }
688 #endif
689