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