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
initio(struct ionod * iop,int save)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 *
simple(s)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 *
getpath(s)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
pathopen(unsigned char * path,unsigned char * name)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 *
catpath(unsigned char * path,unsigned char * name)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 *
nextpath(unsigned char * path)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
execa(unsigned char * at[],short pos)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 *
execs(unsigned char * ap,unsigned char * t[])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
trim(unsigned char * at)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
trims(at)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 *
mactrim(s)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 **
scan(argn)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
gsort(from,to)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
getarg(ac)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
split(s)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
suspacct(void)622 suspacct(void)
623 {
624 shaccton = 0;
625 }
626
627 void
preacct(unsigned char * cmdadr)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
doacct(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
compress(clock_t 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