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