1 /* $OpenBSD: exp.c,v 1.7 2003/06/11 21:09:50 deraadt Exp $ */ 2 /* $NetBSD: exp.c,v 1.6 1995/03/21 09:02:51 cgd Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)exp.c 8.1 (Berkeley) 5/31/93"; 36 #else 37 static char rcsid[] = "$OpenBSD: exp.c,v 1.7 2003/06/11 21:09:50 deraadt Exp $"; 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <stdlib.h> 44 #include <unistd.h> 45 #ifndef SHORT_STRINGS 46 #include <string.h> 47 #endif /* SHORT_STRINGS */ 48 #include <stdarg.h> 49 50 #include "csh.h" 51 #include "extern.h" 52 53 #define IGNORE 1 /* in ignore, it means to ignore value, just parse */ 54 #define NOGLOB 2 /* in ignore, it means not to globone */ 55 56 #define ADDOP 1 57 #define MULOP 2 58 #define EQOP 4 59 #define RELOP 8 60 #define RESTOP 16 61 #define ANYOP 31 62 63 #define EQEQ 1 64 #define GTR 2 65 #define LSS 4 66 #define NOTEQ 6 67 #define EQMATCH 7 68 #define NOTEQMATCH 8 69 70 static int exp1(Char ***, bool); 71 static int exp2(Char ***, bool); 72 static int exp2a(Char ***, bool); 73 static int exp2b(Char ***, bool); 74 static int exp2c(Char ***, bool); 75 static Char * exp3(Char ***, bool); 76 static Char * exp3a(Char ***, bool); 77 static Char * exp4(Char ***, bool); 78 static Char * exp5(Char ***, bool); 79 static Char * exp6(Char ***, bool); 80 static void evalav(Char **); 81 static int isa(Char *, int); 82 static int egetn(Char *); 83 84 #ifdef EDEBUG 85 static void etracc(char *, Char *, Char ***); 86 static void etraci(char *, int, Char ***); 87 #endif 88 89 int 90 expr(Char ***vp) 91 { 92 return (exp0(vp, 0)); 93 } 94 95 int 96 exp0(Char ***vp, bool ignore) 97 { 98 int p1 = exp1(vp, ignore); 99 100 #ifdef EDEBUG 101 etraci("exp0 p1", p1, vp); 102 #endif 103 if (**vp && eq(**vp, STRor2)) { 104 int p2; 105 106 (*vp)++; 107 p2 = exp0(vp, (ignore & IGNORE) || p1); 108 #ifdef EDEBUG 109 etraci("exp0 p2", p2, vp); 110 #endif 111 return (p1 || p2); 112 } 113 return (p1); 114 } 115 116 static int 117 exp1(Char ***vp, bool ignore) 118 { 119 int p1 = exp2(vp, ignore); 120 121 #ifdef EDEBUG 122 etraci("exp1 p1", p1, vp); 123 #endif 124 if (**vp && eq(**vp, STRand2)) { 125 int p2; 126 127 (*vp)++; 128 p2 = exp1(vp, (ignore & IGNORE) || !p1); 129 #ifdef EDEBUG 130 etraci("exp1 p2", p2, vp); 131 #endif 132 return (p1 && p2); 133 } 134 return (p1); 135 } 136 137 static int 138 exp2(Char ***vp, bool ignore) 139 { 140 int p1 = exp2a(vp, ignore); 141 142 #ifdef EDEBUG 143 etraci("exp3 p1", p1, vp); 144 #endif 145 if (**vp && eq(**vp, STRor)) { 146 int p2; 147 148 (*vp)++; 149 p2 = exp2(vp, ignore); 150 #ifdef EDEBUG 151 etraci("exp3 p2", p2, vp); 152 #endif 153 return (p1 | p2); 154 } 155 return (p1); 156 } 157 158 static int 159 exp2a(Char ***vp, bool ignore) 160 { 161 int p1 = exp2b(vp, ignore); 162 163 #ifdef EDEBUG 164 etraci("exp2a p1", p1, vp); 165 #endif 166 if (**vp && eq(**vp, STRcaret)) { 167 int p2; 168 169 (*vp)++; 170 p2 = exp2a(vp, ignore); 171 #ifdef EDEBUG 172 etraci("exp2a p2", p2, vp); 173 #endif 174 return (p1 ^ p2); 175 } 176 return (p1); 177 } 178 179 static int 180 exp2b(Char ***vp, bool ignore) 181 { 182 int p1 = exp2c(vp, ignore); 183 184 #ifdef EDEBUG 185 etraci("exp2b p1", p1, vp); 186 #endif 187 if (**vp && eq(**vp, STRand)) { 188 int p2; 189 190 (*vp)++; 191 p2 = exp2b(vp, ignore); 192 #ifdef EDEBUG 193 etraci("exp2b p2", p2, vp); 194 #endif 195 return (p1 & p2); 196 } 197 return (p1); 198 } 199 200 static int 201 exp2c(Char ***vp, bool ignore) 202 { 203 Char *p1 = exp3(vp, ignore); 204 Char *p2; 205 int i; 206 207 #ifdef EDEBUG 208 etracc("exp2c p1", p1, vp); 209 #endif 210 if ((i = isa(**vp, EQOP)) != 0) { 211 (*vp)++; 212 if (i == EQMATCH || i == NOTEQMATCH) 213 ignore |= NOGLOB; 214 p2 = exp3(vp, ignore); 215 #ifdef EDEBUG 216 etracc("exp2c p2", p2, vp); 217 #endif 218 if (!(ignore & IGNORE)) 219 switch (i) { 220 221 case EQEQ: 222 i = eq(p1, p2); 223 break; 224 225 case NOTEQ: 226 i = !eq(p1, p2); 227 break; 228 229 case EQMATCH: 230 i = Gmatch(p1, p2); 231 break; 232 233 case NOTEQMATCH: 234 i = !Gmatch(p1, p2); 235 break; 236 } 237 xfree((ptr_t) p1); 238 xfree((ptr_t) p2); 239 return (i); 240 } 241 i = egetn(p1); 242 xfree((ptr_t) p1); 243 return (i); 244 } 245 246 static Char * 247 exp3(Char ***vp, bool ignore) 248 { 249 Char *p1, *p2; 250 int i; 251 252 p1 = exp3a(vp, ignore); 253 #ifdef EDEBUG 254 etracc("exp3 p1", p1, vp); 255 #endif 256 if ((i = isa(**vp, RELOP)) != 0) { 257 (*vp)++; 258 if (**vp && eq(**vp, STRequal)) 259 i |= 1, (*vp)++; 260 p2 = exp3(vp, ignore); 261 #ifdef EDEBUG 262 etracc("exp3 p2", p2, vp); 263 #endif 264 if (!(ignore & IGNORE)) 265 switch (i) { 266 267 case GTR: 268 i = egetn(p1) > egetn(p2); 269 break; 270 271 case GTR | 1: 272 i = egetn(p1) >= egetn(p2); 273 break; 274 275 case LSS: 276 i = egetn(p1) < egetn(p2); 277 break; 278 279 case LSS | 1: 280 i = egetn(p1) <= egetn(p2); 281 break; 282 } 283 xfree((ptr_t) p1); 284 xfree((ptr_t) p2); 285 return (putn(i)); 286 } 287 return (p1); 288 } 289 290 static Char * 291 exp3a(Char ***vp, bool ignore) 292 { 293 Char *p1, *p2, *op; 294 int i; 295 296 p1 = exp4(vp, ignore); 297 #ifdef EDEBUG 298 etracc("exp3a p1", p1, vp); 299 #endif 300 op = **vp; 301 if (op && any("<>", op[0]) && op[0] == op[1]) { 302 (*vp)++; 303 p2 = exp3a(vp, ignore); 304 #ifdef EDEBUG 305 etracc("exp3a p2", p2, vp); 306 #endif 307 if (op[0] == '<') 308 i = egetn(p1) << egetn(p2); 309 else 310 i = egetn(p1) >> egetn(p2); 311 xfree((ptr_t) p1); 312 xfree((ptr_t) p2); 313 return (putn(i)); 314 } 315 return (p1); 316 } 317 318 static Char * 319 exp4(Char ***vp, bool ignore) 320 { 321 Char *p1, *p2; 322 int i = 0; 323 324 p1 = exp5(vp, ignore); 325 #ifdef EDEBUG 326 etracc("exp4 p1", p1, vp); 327 #endif 328 if (isa(**vp, ADDOP)) { 329 Char *op = *(*vp)++; 330 331 p2 = exp4(vp, ignore); 332 #ifdef EDEBUG 333 etracc("exp4 p2", p2, vp); 334 #endif 335 if (!(ignore & IGNORE)) 336 switch (op[0]) { 337 338 case '+': 339 i = egetn(p1) + egetn(p2); 340 break; 341 342 case '-': 343 i = egetn(p1) - egetn(p2); 344 break; 345 } 346 xfree((ptr_t) p1); 347 xfree((ptr_t) p2); 348 return (putn(i)); 349 } 350 return (p1); 351 } 352 353 static Char * 354 exp5(Char ***vp, bool ignore) 355 { 356 Char *p1, *p2; 357 int i = 0; 358 359 p1 = exp6(vp, ignore); 360 #ifdef EDEBUG 361 etracc("exp5 p1", p1, vp); 362 #endif 363 if (isa(**vp, MULOP)) { 364 Char *op = *(*vp)++; 365 366 p2 = exp5(vp, ignore); 367 #ifdef EDEBUG 368 etracc("exp5 p2", p2, vp); 369 #endif 370 if (!(ignore & IGNORE)) 371 switch (op[0]) { 372 373 case '*': 374 i = egetn(p1) * egetn(p2); 375 break; 376 377 case '/': 378 i = egetn(p2); 379 if (i == 0) 380 stderror(ERR_DIV0); 381 i = egetn(p1) / i; 382 break; 383 384 case '%': 385 i = egetn(p2); 386 if (i == 0) 387 stderror(ERR_MOD0); 388 i = egetn(p1) % i; 389 break; 390 } 391 xfree((ptr_t) p1); 392 xfree((ptr_t) p2); 393 return (putn(i)); 394 } 395 return (p1); 396 } 397 398 static Char * 399 exp6(Char ***vp, bool ignore) 400 { 401 int ccode, i = 0; 402 Char *cp, *dp, *ep; 403 404 if (**vp == 0) 405 stderror(ERR_NAME | ERR_EXPRESSION); 406 if (eq(**vp, STRbang)) { 407 (*vp)++; 408 cp = exp6(vp, ignore); 409 #ifdef EDEBUG 410 etracc("exp6 ! cp", cp, vp); 411 #endif 412 i = egetn(cp); 413 xfree((ptr_t) cp); 414 return (putn(!i)); 415 } 416 if (eq(**vp, STRtilde)) { 417 (*vp)++; 418 cp = exp6(vp, ignore); 419 #ifdef EDEBUG 420 etracc("exp6 ~ cp", cp, vp); 421 #endif 422 i = egetn(cp); 423 xfree((ptr_t) cp); 424 return (putn(~i)); 425 } 426 if (eq(**vp, STRLparen)) { 427 (*vp)++; 428 ccode = exp0(vp, ignore); 429 #ifdef EDEBUG 430 etraci("exp6 () ccode", ccode, vp); 431 #endif 432 if (*vp == 0 || **vp == 0 || ***vp != ')') 433 stderror(ERR_NAME | ERR_EXPRESSION); 434 (*vp)++; 435 return (putn(ccode)); 436 } 437 if (eq(**vp, STRLbrace)) { 438 Char **v; 439 struct command faket; 440 Char *fakecom[2]; 441 442 faket.t_dtyp = NODE_COMMAND; 443 faket.t_dflg = 0; 444 faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL; 445 faket.t_dcom = fakecom; 446 fakecom[0] = STRfakecom; 447 fakecom[1] = NULL; 448 (*vp)++; 449 v = *vp; 450 for (;;) { 451 if (!**vp) 452 stderror(ERR_NAME | ERR_MISSING, '}'); 453 if (eq(*(*vp)++, STRRbrace)) 454 break; 455 } 456 if (ignore & IGNORE) 457 return (Strsave(STRNULL)); 458 psavejob(); 459 if (pfork(&faket, -1) == 0) { 460 *--(*vp) = 0; 461 evalav(v); 462 exitstat(); 463 } 464 pwait(); 465 prestjob(); 466 #ifdef EDEBUG 467 etraci("exp6 {} status", egetn(value(STRstatus)), vp); 468 #endif 469 return (putn(egetn(value(STRstatus)) == 0)); 470 } 471 if (isa(**vp, ANYOP)) 472 return (Strsave(STRNULL)); 473 cp = *(*vp)++; 474 if (*cp == '-' && any("erwxfdzopls", cp[1])) { 475 struct stat stb; 476 477 if (cp[2] != '\0') 478 stderror(ERR_NAME | ERR_FILEINQ); 479 /* 480 * Detect missing file names by checking for operator in the file name 481 * position. However, if an operator name appears there, we must make 482 * sure that there's no file by that name (e.g., "/") before announcing 483 * an error. Even this check isn't quite right, since it doesn't take 484 * globbing into account. 485 */ 486 if (isa(**vp, ANYOP) && stat(short2str(**vp), &stb)) 487 stderror(ERR_NAME | ERR_FILENAME); 488 489 dp = *(*vp)++; 490 if (ignore & IGNORE) 491 return (Strsave(STRNULL)); 492 ep = globone(dp, G_ERROR); 493 switch (cp[1]) { 494 495 case 'r': 496 i = !access(short2str(ep), R_OK); 497 break; 498 499 case 'w': 500 i = !access(short2str(ep), W_OK); 501 break; 502 503 case 'x': 504 i = !access(short2str(ep), X_OK); 505 break; 506 507 default: 508 if ( 509 #ifdef S_IFLNK 510 cp[1] == 'l' ? lstat(short2str(ep), &stb) : 511 #endif 512 stat(short2str(ep), &stb)) { 513 xfree((ptr_t) ep); 514 return (Strsave(STR0)); 515 } 516 switch (cp[1]) { 517 518 case 'f': 519 i = S_ISREG(stb.st_mode); 520 break; 521 522 case 'd': 523 i = S_ISDIR(stb.st_mode); 524 break; 525 526 case 'p': 527 #ifdef S_ISFIFO 528 i = S_ISFIFO(stb.st_mode); 529 #else 530 i = 0; 531 #endif 532 break; 533 534 case 'l': 535 #ifdef S_ISLNK 536 i = S_ISLNK(stb.st_mode); 537 #else 538 i = 0; 539 #endif 540 break; 541 542 case 's': 543 #ifdef S_ISSOCK 544 i = S_ISSOCK(stb.st_mode); 545 #else 546 i = 0; 547 #endif 548 break; 549 550 case 'z': 551 i = stb.st_size == 0; 552 break; 553 554 case 'e': 555 i = 1; 556 break; 557 558 case 'o': 559 i = stb.st_uid == uid; 560 break; 561 } 562 } 563 #ifdef EDEBUG 564 etraci("exp6 -? i", i, vp); 565 #endif 566 xfree((ptr_t) ep); 567 return (putn(i)); 568 } 569 #ifdef EDEBUG 570 etracc("exp6 default", cp, vp); 571 #endif 572 return (ignore & NOGLOB ? Strsave(cp) : globone(cp, G_ERROR)); 573 } 574 575 static void 576 evalav(Char **v) 577 { 578 struct wordent paraml1; 579 struct wordent *hp = ¶ml1; 580 struct command *t; 581 struct wordent *wdp = hp; 582 583 set(STRstatus, Strsave(STR0)); 584 hp->prev = hp->next = hp; 585 hp->word = STRNULL; 586 while (*v) { 587 struct wordent *new = 588 (struct wordent *) xcalloc(1, sizeof *wdp); 589 590 new->prev = wdp; 591 new->next = hp; 592 wdp->next = new; 593 wdp = new; 594 wdp->word = Strsave(*v++); 595 } 596 hp->prev = wdp; 597 alias(¶ml1); 598 t = syntax(paraml1.next, ¶ml1, 0); 599 if (seterr) 600 stderror(ERR_OLD); 601 execute(t, -1, NULL, NULL); 602 freelex(¶ml1), freesyn(t); 603 } 604 605 static int 606 isa(Char *cp, int what) 607 { 608 if (cp == 0) 609 return ((what & RESTOP) != 0); 610 if (cp[1] == 0) { 611 if (what & ADDOP && (*cp == '+' || *cp == '-')) 612 return (1); 613 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%')) 614 return (1); 615 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' || 616 *cp == '~' || *cp == '^' || *cp == '"')) 617 return (1); 618 } 619 else if (cp[2] == 0) { 620 if (what & RESTOP) { 621 if (cp[0] == '|' && cp[1] == '&') 622 return (1); 623 if (cp[0] == '<' && cp[1] == '<') 624 return (1); 625 if (cp[0] == '>' && cp[1] == '>') 626 return (1); 627 } 628 if (what & EQOP) { 629 if (cp[0] == '=') { 630 if (cp[1] == '=') 631 return (EQEQ); 632 if (cp[1] == '~') 633 return (EQMATCH); 634 } 635 else if (cp[0] == '!') { 636 if (cp[1] == '=') 637 return (NOTEQ); 638 if (cp[1] == '~') 639 return (NOTEQMATCH); 640 } 641 } 642 } 643 if (what & RELOP) { 644 if (*cp == '<') 645 return (LSS); 646 if (*cp == '>') 647 return (GTR); 648 } 649 return (0); 650 } 651 652 static int 653 egetn(Char *cp) 654 { 655 if (*cp && *cp != '-' && !Isdigit(*cp)) 656 stderror(ERR_NAME | ERR_EXPRESSION); 657 return (getn(cp)); 658 } 659 660 /* Phew! */ 661 662 #ifdef EDEBUG 663 static void 664 etraci(char *str, int i, Char ***vp) 665 { 666 (void) fprintf(csherr, "%s=%d\t", str, i); 667 blkpr(csherr, *vp); 668 (void) fprintf(csherr, "\n"); 669 } 670 static void 671 etracc(char *str, Char *cp, Char ***vp) 672 { 673 (void) fprintf(csherr, "%s=%s\t", str, vis_str(cp)); 674 blkpr(csherr, *vp); 675 (void) fprintf(csherr, "\n"); 676 } 677 #endif 678