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