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