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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 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 "sym.h" 35 #include <wait.h> 36 37 static unsigned char quote; /* used locally */ 38 static unsigned char quoted; /* used locally */ 39 static int getch(); 40 static void comsubst(int); 41 static void flush(int); 42 43 static void 44 copyto(unsigned char endch, int trimflag) 45 /* trimflag - flag to check if argument will be trimmed */ 46 { 47 unsigned int c; 48 unsigned int d; 49 unsigned char *pc; 50 51 while ((c = getch(endch, trimflag)) != endch && c) 52 if (quote) { 53 if(c == '\\') { /* don't interpret next character */ 54 if (staktop >= brkend) 55 growstak(staktop); 56 pushstak(c); 57 d = readwc(); 58 if(!escchar(d)) { /* both \ and following 59 character are quoted if next 60 character is not $, `, ", or \*/ 61 if (staktop >= brkend) 62 growstak(staktop); 63 pushstak('\\'); 64 if (staktop >= brkend) 65 growstak(staktop); 66 pushstak('\\'); 67 pc = readw(d); 68 /* push entire multibyte char */ 69 while(*pc) { 70 if (staktop >= brkend) 71 growstak(staktop); 72 pushstak(*pc++); 73 } 74 } else { 75 pc = readw(d); 76 /* d might be NULL */ 77 /* Evenif d is NULL, we have to save it */ 78 if (*pc) { 79 while (*pc) { 80 if (staktop >= brkend) 81 growstak(staktop); 82 pushstak(*pc++); 83 } 84 } else { 85 if (staktop >= brkend) 86 growstak(staktop); 87 pushstak(*pc); 88 } 89 } 90 } else { /* push escapes onto stack to quote characters */ 91 pc = readw(c); 92 if (staktop >= brkend) 93 growstak(staktop); 94 pushstak('\\'); 95 while(*pc) { 96 if (staktop >= brkend) 97 growstak(staktop); 98 pushstak(*pc++); 99 } 100 } 101 } else if(c == '\\') { 102 c = readwc(); /* get character to be escaped */ 103 if (staktop >= brkend) 104 growstak(staktop); 105 pushstak('\\'); 106 pc = readw(c); 107 /* c might be NULL */ 108 /* Evenif c is NULL, we have to save it */ 109 if (*pc) { 110 while (*pc) { 111 if (staktop >= brkend) 112 growstak(staktop); 113 pushstak(*pc++); 114 } 115 } else { 116 if (staktop >= brkend) 117 growstak(staktop); 118 pushstak(*pc); 119 } 120 } else { 121 pc = readw(c); 122 while (*pc) { 123 if (staktop >= brkend) 124 growstak(staktop); 125 pushstak(*pc++); 126 } 127 } 128 if (staktop >= brkend) 129 growstak(staktop); 130 zerostak(); 131 if (c != endch) 132 error(badsub); 133 } 134 135 static void 136 skipto(unsigned char endch) 137 { 138 /* 139 * skip chars up to } 140 */ 141 unsigned int c; 142 143 while ((c = readwc()) && c != endch) 144 { 145 switch (c) 146 { 147 case SQUOTE: 148 skipto(SQUOTE); 149 break; 150 151 case DQUOTE: 152 skipto(DQUOTE); 153 break; 154 155 case DOLLAR: 156 if (readwc() == BRACE) 157 skipto('}'); 158 } 159 } 160 if (c != endch) 161 error(badsub); 162 } 163 164 static 165 int getch(endch, trimflag) 166 unsigned char endch; 167 int trimflag; /* flag to check if an argument is going to be trimmed, here document 168 output is never trimmed 169 */ 170 { 171 unsigned int d; 172 int atflag; /* flag to check if $@ has already been seen within double 173 quotes */ 174 retry: 175 d = readwc(); 176 if (!subchar(d)) 177 return(d); 178 179 if (d == DOLLAR) 180 { 181 unsigned int c; 182 183 if ((c = readwc(), dolchar(c))) 184 { 185 struct namnod *n = (struct namnod *)NIL; 186 int dolg = 0; 187 BOOL bra; 188 BOOL nulflg; 189 unsigned char *argp, *v; 190 unsigned char idb[2]; 191 unsigned char *id = idb; 192 193 if (bra = (c == BRACE)) 194 c = readwc(); 195 if (letter(c)) 196 { 197 argp = (unsigned char *)relstak(); 198 while (alphanum(c)) 199 { 200 if (staktop >= brkend) 201 growstak(staktop); 202 pushstak(c); 203 c = readwc(); 204 } 205 if (staktop >= brkend) 206 growstak(staktop); 207 zerostak(); 208 n = lookup(absstak(argp)); 209 setstak(argp); 210 if (n->namflg & N_FUNCTN) 211 error(badsub); 212 v = n->namval; 213 id = (unsigned char *)n->namid; 214 peekc = c | MARK; 215 } 216 else if (digchar(c)) 217 { 218 *id = c; 219 idb[1] = 0; 220 if (astchar(c)) 221 { 222 if(c == '@' && !atflag && quote) { 223 quoted--; 224 atflag = 1; 225 } 226 dolg = 1; 227 c = '1'; 228 } 229 c -= '0'; 230 v = ((c == 0) ? cmdadr : ((int)c <= dolc) ? dolv[c] : (unsigned char *)(dolg = 0)); 231 } 232 else if (c == '$') 233 v = pidadr; 234 else if (c == '!') 235 v = pcsadr; 236 else if (c == '#') 237 { 238 itos(dolc); 239 v = numbuf; 240 } 241 else if (c == '?') 242 { 243 itos(retval); 244 v = numbuf; 245 } 246 else if (c == '-') 247 v = flagadr; 248 else if (bra) 249 error(badsub); 250 else 251 goto retry; 252 c = readwc(); 253 if (c == ':' && bra) /* null and unset fix */ 254 { 255 nulflg = 1; 256 c = readwc(); 257 } 258 else 259 nulflg = 0; 260 if (!defchar(c) && bra) 261 error(badsub); 262 argp = 0; 263 if (bra) 264 { 265 if (c != '}') 266 { 267 argp = (unsigned char *)relstak(); 268 if ((v == 0 || (nulflg && *v == 0)) ^ (setchar(c))) 269 copyto('}', trimflag); 270 else 271 skipto('}'); 272 argp = absstak(argp); 273 } 274 } 275 else 276 { 277 peekc = c | MARK; 278 c = 0; 279 } 280 if (v && (!nulflg || *v)) 281 { 282 283 if (c != '+') 284 { 285 for (;;) 286 { 287 if (*v == 0 && quote) { 288 if (staktop >= brkend) 289 growstak(staktop); 290 pushstak('\\'); 291 if (staktop >= brkend) 292 growstak(staktop); 293 pushstak('\0'); 294 } else { 295 while (c = *v) { 296 wchar_t wc; 297 int length; 298 if ((length = mbtowc(&wc, (char *)v, MB_LEN_MAX)) <= 0) 299 length = 1; 300 301 if(quote || (c == '\\' && trimflag)) { 302 if (staktop >= brkend) 303 growstak(staktop); 304 pushstak('\\'); 305 } 306 while(length-- > 0) { 307 if (staktop >= brkend) 308 growstak(staktop); 309 pushstak(*v++); 310 } 311 } 312 } 313 314 if (dolg == 0 || (++dolg > dolc)) 315 break; 316 else /* $* and $@ expansion */ 317 { 318 v = dolv[dolg]; 319 if(*id == '*' && quote) { 320 /* push quoted space so that " $* " will not be broken into separate arguments */ 321 if (staktop >= brkend) 322 growstak(staktop); 323 pushstak('\\'); 324 } 325 if (staktop >= brkend) 326 growstak(staktop); 327 pushstak(' '); 328 } 329 } 330 } 331 } 332 else if (argp) 333 { 334 if (c == '?') { 335 if(trimflag) 336 trim(argp); 337 failed(id, *argp ? (const char *)argp : 338 badparam); 339 } 340 else if (c == '=') 341 { 342 if (n) 343 { 344 int strlngth = staktop - stakbot; 345 unsigned char *savptr = fixstak(); 346 unsigned char *newargp; 347 /* 348 * copy word onto stack, trim it, and then 349 * do assignment 350 */ 351 usestak(); 352 while(c = *argp) { 353 wchar_t wc; 354 int len; 355 356 if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0) 357 len = 1; 358 359 if(c == '\\' && trimflag) { 360 argp++; 361 if (*argp == 0) { 362 argp++; 363 continue; 364 } 365 if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0) 366 len = 1; 367 } 368 while(len-- > 0) { 369 if (staktop >= brkend) 370 growstak(staktop); 371 pushstak(*argp++); 372 } 373 } 374 newargp = fixstak(); 375 assign(n, newargp); 376 tdystak(savptr); 377 (void) memcpystak(stakbot, savptr, strlngth); 378 staktop = stakbot + strlngth; 379 } 380 else 381 error(badsub); 382 } 383 } 384 else if (flags & setflg) 385 failed(id, unset); 386 goto retry; 387 } 388 else 389 peekc = c | MARK; 390 } 391 else if (d == endch) 392 return(d); 393 else if (d == SQUOTE) 394 { 395 comsubst(trimflag); 396 goto retry; 397 } 398 else if (d == DQUOTE && trimflag) 399 { 400 if(!quote) { 401 atflag = 0; 402 quoted++; 403 } 404 quote ^= QUOTE; 405 goto retry; 406 } 407 return(d); 408 } 409 410 unsigned char * 411 macro(as) 412 unsigned char *as; 413 { 414 /* 415 * Strip "" and do $ substitution 416 * Leaves result on top of stack 417 */ 418 BOOL savqu = quoted; 419 unsigned char savq = quote; 420 struct filehdr fb; 421 422 push(&fb); 423 estabf(as); 424 usestak(); 425 quote = 0; 426 quoted = 0; 427 copyto(0, 1); 428 pop(); 429 if (quoted && (stakbot == staktop)) { 430 if (staktop >= brkend) 431 growstak(staktop); 432 pushstak('\\'); 433 if (staktop >= brkend) 434 growstak(staktop); 435 pushstak('\0'); 436 /* 437 * above is the fix for *'.c' bug 438 */ 439 } 440 quote = savq; 441 quoted = savqu; 442 return(fixstak()); 443 } 444 /* Save file descriptor for command substitution */ 445 int savpipe = -1; 446 447 static void 448 comsubst(int trimflag) 449 /* trimflag - used to determine if argument will later be trimmed */ 450 { 451 /* 452 * command substn 453 */ 454 struct fileblk cb; 455 unsigned int d; 456 int strlngth = staktop - stakbot; 457 unsigned char *oldstaktop; 458 unsigned char *savptr = fixstak(); 459 unsigned char *pc; 460 461 usestak(); 462 while ((d = readwc()) != SQUOTE && d) { 463 if(d == '\\') { 464 d = readwc(); 465 if(!escchar(d) || (d == '"' && !quote)) { 466 /* trim quotes for `, \, or " if command substitution is within 467 double quotes */ 468 if (staktop >= brkend) 469 growstak(staktop); 470 pushstak('\\'); 471 } 472 } 473 pc = readw(d); 474 /* d might be NULL */ 475 if (*pc) { 476 while (*pc) { 477 if (staktop >= brkend) 478 growstak(staktop); 479 pushstak(*pc++); 480 } 481 } else { 482 if (staktop >= brkend) 483 growstak(staktop); 484 pushstak(*pc); 485 } 486 } 487 { 488 unsigned char *argc; 489 490 argc = fixstak(); 491 push(&cb); 492 estabf(argc); /* read from string */ 493 } 494 { 495 struct trenod *t; 496 int pv[2]; 497 498 /* 499 * this is done like this so that the pipe 500 * is open only when needed 501 */ 502 t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG )); 503 chkpipe(pv); 504 savpipe = pv[OTPIPE]; 505 initf(pv[INPIPE]); /* read from pipe */ 506 execute(t, XEC_NOSTOP, (int)(flags & errflg), 0, pv); 507 close(pv[OTPIPE]); 508 savpipe = -1; 509 } 510 tdystak(savptr); 511 (void) memcpystak(stakbot, savptr, strlngth); 512 oldstaktop = staktop = stakbot + strlngth; 513 while (d = readwc()) { 514 if(quote || (d == '\\' && trimflag)) { 515 unsigned char *rest; 516 /* quote output from command subst. if within double 517 quotes or backslash part of output */ 518 rest = readw(d); 519 if (staktop >= brkend) 520 growstak(staktop); 521 pushstak('\\'); 522 while(d = *rest++) { 523 /* Pick up all of multibyte character */ 524 if (staktop >= brkend) 525 growstak(staktop); 526 pushstak(d); 527 } 528 } 529 else { 530 pc = readw(d); 531 while (*pc) { 532 if (staktop >= brkend) 533 growstak(staktop); 534 pushstak(*pc++); 535 } 536 } 537 } 538 { 539 extern pid_t parent; 540 int stat; 541 int rc; 542 int ret = 0; 543 544 while ((ret = waitpid(parent,&stat,0)) != parent) { 545 /* break out if waitpid(2) has failed */ 546 if (ret == -1) 547 break; 548 } 549 if (WIFEXITED(stat)) 550 rc = WEXITSTATUS(stat); 551 else 552 rc = (WTERMSIG(stat) | SIGFLG); 553 if (rc && (flags & errflg)) 554 exitsh(rc); 555 exitval = rc; 556 flags |= eflag; 557 exitset(); 558 } 559 while (oldstaktop != staktop) 560 { /* strip off trailing newlines from command substitution only */ 561 if ((*--staktop) != NL) 562 { 563 ++staktop; 564 break; 565 } else if(quote) 566 staktop--; /* skip past backslashes if quoting */ 567 } 568 pop(); 569 } 570 571 #define CPYSIZ 512 572 573 void 574 subst(int in, int ot) 575 { 576 unsigned int c; 577 struct fileblk fb; 578 int count = CPYSIZ; 579 unsigned char *pc; 580 581 push(&fb); 582 initf(in); 583 /* 584 * DQUOTE used to stop it from quoting 585 */ 586 while (c = (getch(DQUOTE, 0))) /* read characters from here document 587 and interpret them */ 588 { 589 if(c == '\\') { 590 c = readwc(); /* check if character in here document is 591 escaped */ 592 if(!escchar(c) || c == '"') { 593 if (staktop >= brkend) 594 growstak(staktop); 595 pushstak('\\'); 596 } 597 } 598 pc = readw(c); 599 /* c might be NULL */ 600 if (*pc) { 601 while (*pc) { 602 if (staktop >= brkend) 603 growstak(staktop); 604 pushstak(*pc++); 605 } 606 } else { 607 if (staktop >= brkend) 608 growstak(staktop); 609 pushstak(*pc); 610 } 611 if (--count == 0) 612 { 613 flush(ot); 614 count = CPYSIZ; 615 } 616 } 617 flush(ot); 618 pop(); 619 } 620 621 static void 622 flush(int ot) 623 { 624 write(ot, stakbot, staktop - stakbot); 625 if (flags & execpr) 626 write(output, stakbot, staktop - stakbot); 627 staktop = stakbot; 628 } 629