1 /*- 2 * Copyright (c) 1980, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)exec.c 5.19 (Berkeley) 07/28/91"; 10 #endif /* not lint */ 11 12 #include <sys/types.h> 13 #include <sys/param.h> 14 #include <dirent.h> 15 #include <fcntl.h> 16 #include <sys/stat.h> 17 #include <errno.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <unistd.h> 21 #if __STDC__ 22 # include <stdarg.h> 23 #else 24 # include <varargs.h> 25 #endif 26 27 #include "csh.h" 28 #include "extern.h" 29 30 /* 31 * System level search and execute of a command. We look in each directory 32 * for the specified command name. If the name contains a '/' then we 33 * execute only the full path name. If there is no search path then we 34 * execute only full path names. 35 */ 36 extern char **environ; 37 38 /* 39 * As we search for the command we note the first non-trivial error 40 * message for presentation to the user. This allows us often 41 * to show that a file has the wrong mode/no access when the file 42 * is not in the last component of the search path, so we must 43 * go on after first detecting the error. 44 */ 45 static char *exerr; /* Execution error message */ 46 static Char *expath; /* Path for exerr */ 47 48 /* 49 * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 50 * to hash execs. If it is allocated (havhash true), then to tell 51 * whether ``name'' is (possibly) present in the i'th component 52 * of the variable path, you look at the bit in xhash indexed by 53 * hash(hashname("name"), i). This is setup automatically 54 * after .login is executed, and recomputed whenever ``path'' is 55 * changed. 56 * The two part hash function is designed to let texec() call the 57 * more expensive hashname() only once and the simple hash() several 58 * times (once for each path component checked). 59 * Byte size is assumed to be 8. 60 */ 61 #define HSHSIZ 8192 /* 1k bytes */ 62 #define HSHMASK (HSHSIZ - 1) 63 #define HSHMUL 243 64 static char xhash[HSHSIZ / 8]; 65 66 #define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK) 67 #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 68 #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 69 static int hits, misses; 70 71 /* Dummy search path for just absolute search when no path */ 72 static Char *justabs[] = {STRNULL, 0}; 73 74 static void pexerr __P((void)); 75 static void texec __P((Char *, Char **)); 76 static int hashname __P((Char *)); 77 static void tellmewhat __P((struct wordent *)); 78 static int executable __P((Char *, Char *, bool)); 79 static int iscommand __P((Char *)); 80 81 82 void 83 /*ARGSUSED*/ 84 doexec(v, t) 85 Char **v; 86 struct command *t; 87 { 88 register Char *dp, **pv, **av, *sav; 89 register struct varent *pathv; 90 register bool slash; 91 register int hashval = 0, hashval1, i; 92 Char *blk[2]; 93 94 /* 95 * Glob the command name. We will search $path even if this does something, 96 * as in sh but not in csh. One special case: if there is no PATH, then we 97 * execute only commands which start with '/'. 98 */ 99 blk[0] = t->t_dcom[0]; 100 blk[1] = 0; 101 gflag = 0, tglob(blk); 102 if (gflag) { 103 pv = globall(blk); 104 if (pv == 0) { 105 setname(short2str(blk[0])); 106 stderror(ERR_NAME | ERR_NOMATCH); 107 } 108 gargv = 0; 109 } 110 else 111 pv = saveblk(blk); 112 113 trim(pv); 114 115 exerr = 0; 116 expath = Strsave(pv[0]); 117 Vexpath = expath; 118 119 pathv = adrof(STRpath); 120 if (pathv == 0 && expath[0] != '/') { 121 blkfree(pv); 122 pexerr(); 123 } 124 slash = any(short2str(expath), '/'); 125 126 /* 127 * Glob the argument list, if necessary. Otherwise trim off the quote bits. 128 */ 129 gflag = 0; 130 av = &t->t_dcom[1]; 131 tglob(av); 132 if (gflag) { 133 av = globall(av); 134 if (av == 0) { 135 blkfree(pv); 136 setname(short2str(expath)); 137 stderror(ERR_NAME | ERR_NOMATCH); 138 } 139 gargv = 0; 140 } 141 else 142 av = saveblk(av); 143 144 blkfree(t->t_dcom); 145 t->t_dcom = blkspl(pv, av); 146 xfree((ptr_t) pv); 147 xfree((ptr_t) av); 148 av = t->t_dcom; 149 trim(av); 150 151 if (*av == NULL || **av == '\0') 152 pexerr(); 153 154 xechoit(av); /* Echo command if -x */ 155 /* 156 * Since all internal file descriptors are set to close on exec, we don't 157 * need to close them explicitly here. Just reorient ourselves for error 158 * messages. 159 */ 160 SHIN = 0; 161 SHOUT = 1; 162 SHERR = 2; 163 OLDSTD = 0; 164 /* 165 * We must do this AFTER any possible forking (like `foo` in glob) so that 166 * this shell can still do subprocesses. 167 */ 168 (void) sigsetmask((sigset_t) 0); 169 /* 170 * If no path, no words in path, or a / in the filename then restrict the 171 * command search. 172 */ 173 if (pathv == 0 || pathv->vec[0] == 0 || slash) 174 pv = justabs; 175 else 176 pv = pathv->vec; 177 sav = Strspl(STRslash, *av);/* / command name for postpending */ 178 Vsav = sav; 179 if (havhash) 180 hashval = hashname(*av); 181 i = 0; 182 hits++; 183 do { 184 /* 185 * Try to save time by looking at the hash table for where this command 186 * could be. If we are doing delayed hashing, then we put the names in 187 * one at a time, as the user enters them. This is kinda like Korn 188 * Shell's "tracked aliases". 189 */ 190 if (!slash && pv[0][0] == '/' && havhash) { 191 hashval1 = hash(hashval, i); 192 if (!bit(xhash, hashval1)) 193 goto cont; 194 } 195 if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 196 texec(*av, av); 197 else { 198 dp = Strspl(*pv, sav); 199 Vdp = dp; 200 texec(dp, av); 201 Vdp = 0; 202 xfree((ptr_t) dp); 203 } 204 misses++; 205 cont: 206 pv++; 207 i++; 208 } while (*pv); 209 hits--; 210 Vsav = 0; 211 xfree((ptr_t) sav); 212 pexerr(); 213 } 214 215 static void 216 pexerr() 217 { 218 /* Couldn't find the damn thing */ 219 if (expath) { 220 setname(short2str(expath)); 221 Vexpath = 0; 222 xfree((ptr_t) expath); 223 expath = 0; 224 } 225 else 226 setname(""); 227 if (exerr) 228 stderror(ERR_NAME | ERR_STRING, exerr); 229 stderror(ERR_NAME | ERR_COMMAND); 230 } 231 232 /* 233 * Execute command f, arg list t. 234 * Record error message if not found. 235 * Also do shell scripts here. 236 */ 237 static void 238 texec(sf, st) 239 Char *sf; 240 register Char **st; 241 { 242 register char **t; 243 register char *f; 244 register struct varent *v; 245 register Char **vp; 246 Char *lastsh[2]; 247 int fd; 248 unsigned char c; 249 Char *st0, **ost; 250 251 /* The order for the conversions is significant */ 252 t = short2blk(st); 253 f = short2str(sf); 254 Vt = t; 255 errno = 0; /* don't use a previous error */ 256 (void) execve(f, t, environ); 257 Vt = 0; 258 blkfree((Char **) t); 259 switch (errno) { 260 261 case ENOEXEC: 262 /* 263 * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 264 * it, don't feed it to the shell if it looks like a binary! 265 */ 266 if ((fd = open(f, O_RDONLY)) != -1) { 267 if (read(fd, (char *) &c, 1) == 1) { 268 if (!Isprint(c) && (c != '\n' && c != '\t')) { 269 (void) close(fd); 270 /* 271 * We *know* what ENOEXEC means. 272 */ 273 stderror(ERR_ARCH, f, strerror(errno)); 274 } 275 } 276 #ifdef _PATH_BSHELL 277 else 278 c = '#'; 279 #endif 280 (void) close(fd); 281 } 282 /* 283 * If there is an alias for shell, then put the words of the alias in 284 * front of the argument list replacing the command name. Note no 285 * interpretation of the words at this point. 286 */ 287 v = adrof1(STRshell, &aliases); 288 if (v == 0) { 289 vp = lastsh; 290 vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH; 291 vp[1] = NULL; 292 #ifdef _PATH_BSHELL 293 if (fd != -1 && c != '#') 294 vp[0] = STR_BSHELL; 295 #endif 296 } 297 else 298 vp = v->vec; 299 st0 = st[0]; 300 st[0] = sf; 301 ost = st; 302 st = blkspl(vp, st); /* Splice up the new arglst */ 303 ost[0] = st0; 304 sf = *st; 305 /* The order for the conversions is significant */ 306 t = short2blk(st); 307 f = short2str(sf); 308 xfree((ptr_t) st); 309 Vt = t; 310 (void) execve(f, t, environ); 311 Vt = 0; 312 blkfree((Char **) t); 313 /* The sky is falling, the sky is falling! */ 314 315 case ENOMEM: 316 stderror(ERR_SYSTEM, f, strerror(errno)); 317 318 case ENOENT: 319 break; 320 321 default: 322 if (exerr == 0) { 323 exerr = strerror(errno); 324 if (expath) 325 xfree((ptr_t) expath); 326 expath = Strsave(sf); 327 Vexpath = expath; 328 } 329 } 330 } 331 332 /*ARGSUSED*/ 333 void 334 execash(v, t) 335 Char **v; 336 register struct command *t; 337 { 338 if (chkstop == 0 && setintr) 339 panystop(0); 340 rechist(); 341 (void) signal(SIGINT, parintr); 342 (void) signal(SIGQUIT, parintr); 343 (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ 344 lshift(t->t_dcom, 1); 345 exiterr = 1; 346 doexec(NULL, t); 347 /* NOTREACHED */ 348 } 349 350 void 351 xechoit(t) 352 Char **t; 353 { 354 if (adrof(STRecho)) { 355 (void) fflush(csherr); 356 blkpr(csherr, t); 357 (void) fputc('\n', csherr); 358 } 359 } 360 361 void 362 /*ARGSUSED*/ 363 dohash(v, t) 364 Char **v; 365 struct command *t; 366 { 367 DIR *dirp; 368 register struct dirent *dp; 369 register int cnt; 370 int i = 0; 371 struct varent *pathv = adrof(STRpath); 372 Char **pv; 373 int hashval; 374 375 havhash = 1; 376 for (cnt = 0; cnt < sizeof xhash; cnt++) 377 xhash[cnt] = 0; 378 if (pathv == 0) 379 return; 380 for (pv = pathv->vec; *pv; pv++, i++) { 381 if (pv[0][0] != '/') 382 continue; 383 dirp = opendir(short2str(*pv)); 384 if (dirp == NULL) 385 continue; 386 while ((dp = readdir(dirp)) != NULL) { 387 if (dp->d_ino == 0) 388 continue; 389 if (dp->d_name[0] == '.' && 390 (dp->d_name[1] == '\0' || 391 dp->d_name[1] == '.' && dp->d_name[2] == '\0')) 392 continue; 393 hashval = hash(hashname(str2short(dp->d_name)), i); 394 bis(xhash, hashval); 395 /* tw_add_comm_name (dp->d_name); */ 396 } 397 (void) closedir(dirp); 398 } 399 } 400 401 void 402 /*ARGSUSED*/ 403 dounhash(v, t) 404 Char **v; 405 struct command *t; 406 { 407 havhash = 0; 408 } 409 410 void 411 /*ARGSUSED*/ 412 hashstat(v, t) 413 Char **v; 414 struct command *t; 415 { 416 if (hits + misses) 417 (void) fprintf(cshout, "%d hits, %d misses, %d%%\n", 418 hits, misses, 100 * hits / (hits + misses)); 419 } 420 421 /* 422 * Hash a command name. 423 */ 424 static int 425 hashname(cp) 426 register Char *cp; 427 { 428 register long h = 0; 429 430 while (*cp) 431 h = hash(h, *cp++); 432 return ((int) h); 433 } 434 435 static int 436 iscommand(name) 437 Char *name; 438 { 439 register Char **pv; 440 register Char *sav; 441 register struct varent *v; 442 register bool slash = any(short2str(name), '/'); 443 register int hashval = 0, hashval1, i; 444 445 v = adrof(STRpath); 446 if (v == 0 || v->vec[0] == 0 || slash) 447 pv = justabs; 448 else 449 pv = v->vec; 450 sav = Strspl(STRslash, name); /* / command name for postpending */ 451 if (havhash) 452 hashval = hashname(name); 453 i = 0; 454 do { 455 if (!slash && pv[0][0] == '/' && havhash) { 456 hashval1 = hash(hashval, i); 457 if (!bit(xhash, hashval1)) 458 goto cont; 459 } 460 if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 461 if (executable(NULL, name, 0)) { 462 xfree((ptr_t) sav); 463 return i + 1; 464 } 465 } 466 else { 467 if (executable(*pv, sav, 0)) { 468 xfree((ptr_t) sav); 469 return i + 1; 470 } 471 } 472 cont: 473 pv++; 474 i++; 475 } while (*pv); 476 xfree((ptr_t) sav); 477 return 0; 478 } 479 480 /* Also by: 481 * Andreas Luik <luik@isaak.isa.de> 482 * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 483 * Azenberstr. 35 484 * D-7000 Stuttgart 1 485 * West-Germany 486 * is the executable() routine below and changes to iscommand(). 487 * Thanks again!! 488 */ 489 490 /* 491 * executable() examines the pathname obtained by concatenating dir and name 492 * (dir may be NULL), and returns 1 either if it is executable by us, or 493 * if dir_ok is set and the pathname refers to a directory. 494 * This is a bit kludgy, but in the name of optimization... 495 */ 496 static int 497 executable(dir, name, dir_ok) 498 Char *dir, *name; 499 bool dir_ok; 500 { 501 struct stat stbuf; 502 Char path[MAXPATHLEN + 1], *dp, *sp; 503 char *strname; 504 505 if (dir && *dir) { 506 for (dp = path, sp = dir; *sp; *dp++ = *sp++) 507 if (dp == &path[MAXPATHLEN + 1]) { 508 *--dp = '\0'; 509 break; 510 } 511 for (sp = name; *sp; *dp++ = *sp++) 512 if (dp == &path[MAXPATHLEN + 1]) { 513 *--dp = '\0'; 514 break; 515 } 516 *dp = '\0'; 517 strname = short2str(path); 518 } 519 else 520 strname = short2str(name); 521 return (stat(strname, &stbuf) != -1 && 522 ((S_ISREG(stbuf.st_mode) && 523 /* save time by not calling access() in the hopeless case */ 524 (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 525 access(strname, X_OK) == 0) || 526 (dir_ok && S_ISDIR(stbuf.st_mode)))); 527 } 528 529 /* The dowhich() is by: 530 * Andreas Luik <luik@isaak.isa.de> 531 * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 532 * Azenberstr. 35 533 * D-7000 Stuttgart 1 534 * West-Germany 535 * Thanks!! 536 */ 537 /*ARGSUSED*/ 538 void 539 dowhich(v, c) 540 register Char **v; 541 struct command *c; 542 { 543 struct wordent lex[3]; 544 struct varent *vp; 545 546 lex[0].next = &lex[1]; 547 lex[1].next = &lex[2]; 548 lex[2].next = &lex[0]; 549 550 lex[0].prev = &lex[2]; 551 lex[1].prev = &lex[0]; 552 lex[2].prev = &lex[1]; 553 554 lex[0].word = STRNULL; 555 lex[2].word = STRret; 556 557 while (*++v) { 558 if (vp = adrof1(*v, &aliases)) { 559 (void) fprintf(cshout, "%s: \t aliased to ", short2str(*v)); 560 blkpr(cshout, vp->vec); 561 (void) fputc('\n', cshout); 562 } 563 else { 564 lex[1].word = *v; 565 tellmewhat(lex); 566 } 567 } 568 } 569 570 static void 571 tellmewhat(lex) 572 struct wordent *lex; 573 { 574 register int i; 575 register struct biltins *bptr; 576 register struct wordent *sp = lex->next; 577 bool aliased = 0; 578 Char *s0, *s1, *s2; 579 Char qc; 580 581 if (adrof1(sp->word, &aliases)) { 582 alias(lex); 583 sp = lex->next; 584 aliased = 1; 585 } 586 587 s0 = sp->word; /* to get the memory freeing right... */ 588 589 /* handle quoted alias hack */ 590 if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 591 (sp->word)++; 592 593 /* do quoting, if it hasn't been done */ 594 s1 = s2 = sp->word; 595 while (*s2) 596 switch (*s2) { 597 case '\'': 598 case '"': 599 qc = *s2++; 600 while (*s2 && *s2 != qc) 601 *s1++ = *s2++ | QUOTE; 602 if (*s2) 603 s2++; 604 break; 605 case '\\': 606 if (*++s2) 607 *s1++ = *s2++ | QUOTE; 608 break; 609 default: 610 *s1++ = *s2++; 611 } 612 *s1 = '\0'; 613 614 for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 615 if (eq(sp->word, str2short(bptr->bname))) { 616 if (aliased) 617 prlex(cshout, lex); 618 (void) fprintf(cshout, "%s: shell built-in command.\n", 619 short2str(sp->word)); 620 sp->word = s0; /* we save and then restore this */ 621 return; 622 } 623 } 624 625 if (i = iscommand(strip(sp->word))) { 626 register Char **pv; 627 register struct varent *v; 628 bool slash = any(short2str(sp->word), '/'); 629 630 v = adrof(STRpath); 631 if (v == 0 || v->vec[0] == 0 || slash) 632 pv = justabs; 633 else 634 pv = v->vec; 635 636 while (--i) 637 pv++; 638 if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 639 sp->word = Strspl(STRdotsl, sp->word); 640 prlex(cshout, lex); 641 xfree((ptr_t) sp->word); 642 sp->word = s0; /* we save and then restore this */ 643 return; 644 } 645 s1 = Strspl(*pv, STRslash); 646 sp->word = Strspl(s1, sp->word); 647 xfree((ptr_t) s1); 648 prlex(cshout, lex); 649 xfree((ptr_t) sp->word); 650 } 651 else { 652 if (aliased) 653 prlex(cshout, lex); 654 (void) fprintf(csherr, "%s: Command not found.\n", short2str(sp->word)); 655 } 656 sp->word = s0; /* we save and then restore this */ 657 } 658