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