1 /* 2 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 5 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 6 /* All Rights Reserved */ 7 8 /* 9 * Copyright (c) 1980 Regents of the University of California. 10 * All rights reserved. The Berkeley Software License Agreement 11 * specifies the terms and conditions for redistribution. 12 */ 13 14 #include "sh.h" 15 #include <dirent.h> 16 #include <string.h> 17 #include "sh.tconst.h" 18 19 20 /* 21 * C shell 22 */ 23 24 /* 25 * System level search and execute of a command. 26 * We look in each directory for the specified command name. 27 * If the name contains a '/' then we execute only the full path name. 28 * If there is no search path then we execute only full path names. 29 */ 30 31 char xhash[HSHSIZ / 8]; 32 tchar **Vav; 33 tchar *Vdp; 34 tchar *Vsav; 35 36 struct varent aliases; 37 bool havhash; 38 static int hits; 39 static int misses; 40 short SHOUT; 41 short SHIN; 42 43 void (*parintr)(); 44 void (*parterm)(); 45 46 /* 47 * As we search for the command we note the first non-trivial error 48 * message for presentation to the user. This allows us often 49 * to show that a file has the wrong mode/no access when the file 50 * is not in the last component of the search path, so we must 51 * go on after first detecting the error. 52 */ 53 char *exerr; /* Execution error message */ 54 55 void pexerr(void); 56 void texec(struct command *, tchar *, tchar **); 57 void xechoit(tchar **); 58 void dohash(char []); 59 60 static void tconvert(struct command *, tchar *, tchar **); 61 62 63 extern DIR *opendir_(tchar *); 64 65 void 66 doexec(struct command *t) 67 { 68 tchar *sav; 69 tchar *dp, **pv, **av; 70 struct varent *v; 71 bool slash; 72 int hashval, hashval1, i; 73 tchar *blk[2]; 74 #ifdef TRACE 75 tprintf("TRACE- doexec()\n"); 76 #endif 77 78 /* 79 * Glob the command name. If this does anything, then we 80 * will execute the command only relative to ".". One special 81 * case: if there is no PATH, then we execute only commands 82 * which start with '/'. 83 */ 84 dp = globone(t->t_dcom[0]); 85 sav = t->t_dcom[0]; 86 exerr = 0; t->t_dcom[0] = dp; 87 setname(dp); 88 xfree(sav); 89 v = adrof(S_path /* "path" */); 90 if (v == 0 && dp[0] != '/') { 91 pexerr(); 92 } 93 slash = gflag; 94 95 /* 96 * Glob the argument list, if necessary. 97 * Otherwise trim off the quote bits. 98 */ 99 gflag = 0; av = &t->t_dcom[1]; 100 tglob(av); 101 if (gflag) { 102 av = glob(av); 103 if (av == 0) 104 error("No match"); 105 } 106 blk[0] = t->t_dcom[0]; 107 blk[1] = 0; 108 av = blkspl(blk, av); 109 #ifdef VFORK 110 Vav = av; 111 #endif 112 trim(av); 113 slash |= any('/', av[0]); 114 115 xechoit(av); /* Echo command if -x */ 116 /* 117 * Since all internal file descriptors are set to close on exec, 118 * we don't need to close them explicitly here. Just reorient 119 * ourselves for error messages. 120 */ 121 SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0; 122 123 /* 124 * We must do this AFTER any possible forking (like `foo` 125 * in glob) so that this shell can still do subprocesses. 126 */ 127 (void) sigsetmask(0); 128 129 /* 130 * If no path, no words in path, or a / in the filename 131 * then restrict the command search. 132 */ 133 if (v == 0 || v->vec[0] == 0 || slash) 134 pv = justabs; 135 else 136 pv = v->vec; 137 /* / command name for postpending */ 138 sav = strspl(S_SLASH /* "/" */, *av); 139 #ifdef VFORK 140 Vsav = sav; 141 #endif 142 if (havhash) 143 hashval = hashname(*av); 144 i = 0; 145 #ifdef VFORK 146 hits++; 147 #endif 148 do { 149 if (!slash && pv[0][0] == '/' && havhash) { 150 hashval1 = hash(hashval, i); 151 if (!bit(xhash, hashval1)) 152 goto cont; 153 } 154 155 /* don't make ./xxx */ 156 if (pv[0][0] == 0 || eq(pv[0], S_DOT /* "." */)) { 157 texec(t, *av, av); 158 } else { 159 dp = strspl(*pv, sav); 160 #ifdef VFORK 161 Vdp = dp; 162 #endif 163 texec(t, dp, av); 164 #ifdef VFORK 165 Vdp = 0; 166 #endif 167 xfree(dp); 168 } 169 #ifdef VFORK 170 misses++; 171 #endif 172 cont: 173 pv++; 174 i++; 175 } while (*pv); 176 #ifdef VFORK 177 hits--; 178 #endif 179 #ifdef VFORK 180 Vsav = 0; 181 Vav = 0; 182 #endif 183 xfree(sav); 184 xfree((char *)av); 185 pexerr(); 186 } 187 188 void 189 pexerr(void) 190 { 191 192 #ifdef TRACE 193 tprintf("TRACE- pexerr()\n"); 194 #endif 195 /* Couldn't find the damn thing */ 196 if (exerr) 197 bferr(exerr); 198 bferr("Command not found"); 199 } 200 201 /* 202 * Execute command f, arg list t. 203 * Record error message if not found. 204 * Also do shell scripts here. 205 */ 206 void 207 texec(struct command *cmd, tchar *f, tchar **t) 208 { 209 struct varent *v; 210 tchar **vp; 211 tchar *lastsh[2]; 212 213 #ifdef TRACE 214 tprintf("TRACE- texec()\n"); 215 #endif 216 /* convert cfname and cargs from tchar to char */ 217 tconvert(cmd, f, t); 218 219 execv(cmd->cfname, cmd->cargs); 220 221 /* 222 * exec returned, free up allocations from above 223 * tconvert(), zero cfname and cargs to prevent 224 * duplicate free() in freesyn() 225 */ 226 xfree(cmd->cfname); 227 chr_blkfree(cmd->cargs); 228 cmd->cfname = (char *)0; 229 cmd->cargs = (char **)0; 230 231 switch (errno) { 232 case ENOEXEC: 233 /* check that this is not a binary file */ 234 { 235 int ff = open_(f, 0); 236 tchar ch[MB_LEN_MAX]; 237 238 if (ff != -1 && read_(ff, ch, 1) == 1 && 239 !isprint(ch[0]) && !isspace(ch[0])) { 240 printf("Cannot execute binary file.\n"); 241 Perror(f); 242 (void) close(ff); 243 unsetfd(ff); 244 return; 245 } 246 (void) close(ff); 247 unsetfd(ff); 248 } 249 /* 250 * If there is an alias for shell, then 251 * put the words of the alias in front of the 252 * argument list replacing the command name. 253 * Note no interpretation of the words at this point. 254 */ 255 v = adrof1(S_shell /* "shell" */, &aliases); 256 if (v == 0) { 257 #ifdef OTHERSH 258 int ff = open_(f, 0); 259 tchar ch[MB_LEN_MAX]; 260 #endif 261 262 vp = lastsh; 263 vp[0] = adrof(S_shell /* "shell" */) ? 264 value(S_shell /* "shell" */) : 265 S_SHELLPATH /* SHELLPATH */; 266 vp[1] = (tchar *) NULL; 267 #ifdef OTHERSH 268 if (ff != -1 && read_(ff, ch, 1) == 1 && ch[0] != '#') 269 vp[0] = S_OTHERSH /* OTHERSH */; 270 (void) close(ff); 271 unsetfd(ff); 272 #endif 273 } else 274 vp = v->vec; 275 t[0] = f; 276 t = blkspl(vp, t); /* Splice up the new arglst */ 277 f = *t; 278 279 tconvert(cmd, f, t); /* convert tchar to char */ 280 281 /* 282 * now done with tchar arg list t, 283 * free the space calloc'd by above blkspl() 284 */ 285 xfree((char *)t); 286 287 execv(cmd->cfname, cmd->cargs); /* exec the command */ 288 289 /* exec returned, same free'ing as above */ 290 xfree(cmd->cfname); 291 chr_blkfree(cmd->cargs); 292 cmd->cfname = (char *)0; 293 cmd->cargs = (char **)0; 294 295 /* The sky is falling, the sky is falling! */ 296 297 case ENOMEM: 298 Perror(f); 299 300 case ENOENT: 301 break; 302 303 default: 304 if (exerr == 0) { 305 exerr = strerror(errno); 306 setname(f); 307 } 308 } 309 } 310 311 312 static void 313 tconvert(struct command *cmd, tchar *fname, tchar **list) 314 { 315 char **rc; 316 int len; 317 318 cmd->cfname = tstostr(NULL, fname); 319 320 len = blklen(list); 321 rc = cmd->cargs = (char **) 322 xcalloc((uint_t)(len + 1), sizeof (char **)); 323 while (len--) 324 *rc++ = tstostr(NULL, *list++); 325 *rc = NULL; 326 } 327 328 329 /*ARGSUSED*/ 330 void 331 execash(tchar **t, struct command *kp) 332 { 333 #ifdef TRACE 334 tprintf("TRACE- execash()\n"); 335 #endif 336 337 rechist(); 338 (void) signal(SIGINT, parintr); 339 (void) signal(SIGQUIT, parintr); 340 (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ 341 lshift(kp->t_dcom, 1); 342 exiterr++; 343 doexec(kp); 344 /*NOTREACHED*/ 345 } 346 347 void 348 xechoit(tchar **t) 349 { 350 #ifdef TRACE 351 tprintf("TRACE- xechoit()\n"); 352 #endif 353 354 if (adrof(S_echo /* "echo" */)) { 355 flush(); 356 haderr = 1; 357 blkpr(t), Putchar('\n'); 358 haderr = 0; 359 } 360 } 361 362 /* 363 * This routine called when user enters "rehash". 364 * Both the path and cdpath caching arrays will 365 * be rehashed, via calling dohash. If either 366 * variable is not set with a value, then dohash 367 * just exits. 368 */ 369 void 370 dorehash(void) 371 { 372 dohash(xhash); 373 dohash(xhash2); 374 } 375 376 /* 377 * Fill up caching arrays for path and cdpath 378 */ 379 void 380 dohash(char cachearray[]) 381 { 382 struct stat stb; 383 DIR *dirp; 384 struct dirent *dp; 385 int cnt; 386 int i = 0; 387 struct varent *v; 388 tchar **pv; 389 int hashval; 390 tchar curdir_[MAXNAMLEN+1]; 391 392 #ifdef TRACE 393 tprintf("TRACE- dohash()\n"); 394 #endif 395 /* Caching $path */ 396 if (cachearray == xhash) { 397 havhash = 1; 398 v = adrof(S_path /* "path" */); 399 } else { /* Caching $cdpath */ 400 havhash2 = 1; 401 v = adrof(S_cdpath /* "cdpath" */); 402 } 403 404 for (cnt = 0; cnt < (HSHSIZ / 8); cnt++) 405 cachearray[cnt] = 0; 406 if (v == 0) 407 return; 408 for (pv = v->vec; *pv; pv++, i++) { 409 if (pv[0][0] != '/') 410 continue; 411 dirp = opendir_(*pv); 412 if (dirp == NULL) 413 continue; 414 if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) { 415 unsetfd(dirp->dd_fd); 416 closedir_(dirp); 417 continue; 418 } 419 while ((dp = readdir(dirp)) != NULL) { 420 if (dp->d_ino == 0) 421 continue; 422 if (dp->d_name[0] == '.' && 423 (dp->d_name[1] == '\0' || 424 dp->d_name[1] == '.' && dp->d_name[2] == '\0')) 425 continue; 426 hashval = hash(hashname(strtots(curdir_, dp->d_name)), 427 i); 428 bis(cachearray, hashval); 429 } 430 unsetfd(dirp->dd_fd); 431 closedir_(dirp); 432 } 433 } 434 435 void 436 dounhash(void) 437 { 438 439 #ifdef TRACE 440 tprintf("TRACE- dounhash()\n"); 441 #endif 442 havhash = 0; 443 havhash2 = 0; 444 } 445 446 #ifdef VFORK 447 void 448 hashstat(void) 449 { 450 #ifdef TRACE 451 tprintf("TRACE- hashstat_()\n"); 452 #endif 453 454 if (hits+misses) 455 printf("%d hits, %d misses, %d%%\n", 456 hits, misses, 100 * hits / (hits + misses)); 457 } 458 #endif 459 460 /* 461 * Hash a command name. 462 */ 463 int 464 hashname(tchar *cp) 465 { 466 long h = 0; 467 468 #ifdef TRACE 469 tprintf("TRACE- hashname()\n"); 470 #endif 471 while (*cp) 472 h = hash(h, *cp++); 473 return ((int)h); 474 } 475