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.17 (Berkeley) 06/17/91"; 10 #endif /* not lint */ 11 12 #include <sys/types.h> 13 #include <dirent.h> 14 #include <fcntl.h> 15 #include <errno.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <unistd.h> 19 #if __STDC__ 20 # include <stdarg.h> 21 #else 22 # include <varargs.h> 23 #endif 24 25 #include "csh.h" 26 #include "extern.h" 27 28 /* 29 * System level search and execute of a command. We look in each directory 30 * for the specified command name. If the name contains a '/' then we 31 * execute only the full path name. If there is no search path then we 32 * execute only full path names. 33 */ 34 extern char **environ; 35 36 /* 37 * As we search for the command we note the first non-trivial error 38 * message for presentation to the user. This allows us often 39 * to show that a file has the wrong mode/no access when the file 40 * is not in the last component of the search path, so we must 41 * go on after first detecting the error. 42 */ 43 static char *exerr; /* Execution error message */ 44 static Char *expath; /* Path for exerr */ 45 46 /* 47 * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 48 * to hash execs. If it is allocated (havhash true), then to tell 49 * whether ``name'' is (possibly) present in the i'th component 50 * of the variable path, you look at the bit in xhash indexed by 51 * hash(hashname("name"), i). This is setup automatically 52 * after .login is executed, and recomputed whenever ``path'' is 53 * changed. 54 * The two part hash function is designed to let texec() call the 55 * more expensive hashname() only once and the simple hash() several 56 * times (once for each path component checked). 57 * Byte size is assumed to be 8. 58 */ 59 #define HSHSIZ 8192 /* 1k bytes */ 60 #define HSHMASK (HSHSIZ - 1) 61 #define HSHMUL 243 62 static char xhash[HSHSIZ / 8]; 63 64 #define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK) 65 #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 66 #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 67 static int hits, misses; 68 69 /* Dummy search path for just absolute search when no path */ 70 static Char *justabs[] = {STRNULL, 0}; 71 72 static void pexerr __P((void)); 73 static void texec __P((Char *, Char **)); 74 static int hashname __P((Char *)); 75 76 void 77 doexec(t) 78 register struct command *t; 79 { 80 register Char *dp, **pv, **av, *sav; 81 register struct varent *v; 82 register bool slash; 83 register int hashval = 0, hashval1, i; 84 Char *blk[2]; 85 86 /* 87 * Glob the command name. We will search $path even if this does something, 88 * as in sh but not in csh. One special case: if there is no PATH, then we 89 * execute only commands which start with '/'. 90 */ 91 blk[0] = t->t_dcom[0]; 92 blk[1] = 0; 93 gflag = 0, tglob(blk); 94 if (gflag) { 95 pv = globall(blk); 96 if (pv == 0) { 97 setname(short2str(blk[0])); 98 stderror(ERR_NAME | ERR_NOMATCH); 99 } 100 gargv = 0; 101 } 102 else 103 pv = saveblk(blk); 104 105 trim(pv); 106 107 exerr = 0; 108 expath = Strsave(pv[0]); 109 Vexpath = expath; 110 111 v = adrof(STRpath); 112 if (v == 0 && expath[0] != '/') { 113 blkfree(pv); 114 pexerr(); 115 } 116 slash = any(short2str(expath), '/'); 117 118 /* 119 * Glob the argument list, if necessary. Otherwise trim off the quote bits. 120 */ 121 gflag = 0; 122 av = &t->t_dcom[1]; 123 tglob(av); 124 if (gflag) { 125 av = globall(av); 126 if (av == 0) { 127 blkfree(pv); 128 setname(short2str(expath)); 129 stderror(ERR_NAME | ERR_NOMATCH); 130 } 131 gargv = 0; 132 } 133 else 134 av = saveblk(av); 135 136 blkfree(t->t_dcom); 137 t->t_dcom = blkspl(pv, av); 138 xfree((ptr_t) pv); 139 xfree((ptr_t) av); 140 av = t->t_dcom; 141 trim(av); 142 143 if (*av == NULL || **av == '\0') 144 pexerr(); 145 146 xechoit(av); /* Echo command if -x */ 147 /* 148 * Since all internal file descriptors are set to close on exec, we don't 149 * need to close them explicitly here. Just reorient ourselves for error 150 * messages. 151 */ 152 SHIN = 0; 153 SHOUT = 1; 154 SHDIAG = 2; 155 OLDSTD = 0; 156 /* 157 * We must do this AFTER any possible forking (like `foo` in glob) so that 158 * this shell can still do subprocesses. 159 */ 160 (void) sigsetmask((sigset_t) 0); 161 /* 162 * If no path, no words in path, or a / in the filename then restrict the 163 * command search. 164 */ 165 if (v == 0 || v->vec[0] == 0 || slash) 166 pv = justabs; 167 else 168 pv = v->vec; 169 sav = Strspl(STRslash, *av);/* / command name for postpending */ 170 Vsav = sav; 171 if (havhash) 172 hashval = hashname(*av); 173 i = 0; 174 hits++; 175 do { 176 /* 177 * Try to save time by looking at the hash table for where this command 178 * could be. If we are doing delayed hashing, then we put the names in 179 * one at a time, as the user enters them. This is kinda like Korn 180 * Shell's "tracked aliases". 181 */ 182 if (!slash && pv[0][0] == '/' && havhash) { 183 hashval1 = hash(hashval, i); 184 if (!bit(xhash, hashval1)) 185 goto cont; 186 } 187 if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 188 texec(*av, av); 189 else { 190 dp = Strspl(*pv, sav); 191 Vdp = dp; 192 texec(dp, av); 193 Vdp = 0; 194 xfree((ptr_t) dp); 195 } 196 misses++; 197 cont: 198 pv++; 199 i++; 200 } while (*pv); 201 hits--; 202 Vsav = 0; 203 xfree((ptr_t) sav); 204 pexerr(); 205 } 206 207 static void 208 pexerr() 209 { 210 /* Couldn't find the damn thing */ 211 if (expath) { 212 setname(short2str(expath)); 213 Vexpath = 0; 214 xfree((ptr_t) expath); 215 expath = 0; 216 } 217 else 218 setname(""); 219 if (exerr) 220 stderror(ERR_NAME | ERR_STRING, exerr); 221 stderror(ERR_NAME | ERR_COMMAND); 222 } 223 224 /* 225 * Execute command f, arg list t. 226 * Record error message if not found. 227 * Also do shell scripts here. 228 */ 229 static void 230 texec(sf, st) 231 Char *sf; 232 register Char **st; 233 { 234 register char **t; 235 register char *f; 236 register struct varent *v; 237 register Char **vp; 238 Char *lastsh[2]; 239 int fd; 240 unsigned char c; 241 Char *st0, **ost; 242 243 /* The order for the conversions is significant */ 244 t = short2blk(st); 245 f = short2str(sf); 246 Vt = t; 247 errno = 0; /* don't use a previous error */ 248 (void) execve(f, t, environ); 249 Vt = 0; 250 blkfree((Char **) t); 251 switch (errno) { 252 253 case ENOEXEC: 254 /* 255 * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 256 * it, don't feed it to the shell if it looks like a binary! 257 */ 258 if ((fd = open(f, O_RDONLY)) != -1) { 259 if (read(fd, (char *) &c, 1) == 1) { 260 if (!Isprint(c) && (c != '\n' && c != '\t')) { 261 (void) close(fd); 262 /* 263 * We *know* what ENOEXEC means. 264 */ 265 stderror(ERR_ARCH, f, strerror(errno)); 266 } 267 } 268 #ifdef _PATH_BSHELL 269 else 270 c = '#'; 271 #endif 272 (void) close(fd); 273 } 274 /* 275 * If there is an alias for shell, then put the words of the alias in 276 * front of the argument list replacing the command name. Note no 277 * interpretation of the words at this point. 278 */ 279 v = adrof1(STRshell, &aliases); 280 if (v == 0) { 281 vp = lastsh; 282 vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH; 283 vp[1] = NULL; 284 #ifdef _PATH_BSHELL 285 if (fd != -1 && c != '#') 286 vp[0] = STR_BSHELL; 287 #endif 288 } 289 else 290 vp = v->vec; 291 st0 = st[0]; 292 st[0] = sf; 293 ost = st; 294 st = blkspl(vp, st); /* Splice up the new arglst */ 295 ost[0] = st0; 296 sf = *st; 297 /* The order for the conversions is significant */ 298 t = short2blk(st); 299 f = short2str(sf); 300 xfree((ptr_t) st); 301 Vt = t; 302 (void) execve(f, t, environ); 303 Vt = 0; 304 blkfree((Char **) t); 305 /* The sky is falling, the sky is falling! */ 306 307 case ENOMEM: 308 stderror(ERR_SYSTEM, f, strerror(errno)); 309 310 case ENOENT: 311 break; 312 313 default: 314 if (exerr == 0) { 315 exerr = strerror(errno); 316 if (expath) 317 xfree((ptr_t) expath); 318 expath = Strsave(sf); 319 Vexpath = expath; 320 } 321 } 322 } 323 324 /*ARGSUSED*/ 325 void 326 execash(t, kp) 327 char **t; 328 register struct command *kp; 329 { 330 if (chkstop == 0 && setintr) 331 panystop(0); 332 rechist(); 333 (void) signal(SIGINT, parintr); 334 (void) signal(SIGQUIT, parintr); 335 (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ 336 lshift(kp->t_dcom, 1); 337 exiterr = 1; 338 doexec(kp); 339 /* NOTREACHED */ 340 } 341 342 void 343 xechoit(t) 344 Char **t; 345 { 346 if (adrof(STRecho)) { 347 flush(); 348 haderr = 1; 349 blkpr(t), xputchar('\n'); 350 haderr = 0; 351 } 352 } 353 354 /*VARARGS0*/ 355 void 356 dohash() 357 { 358 DIR *dirp; 359 register struct dirent *dp; 360 register int cnt; 361 int i = 0; 362 struct varent *v = adrof(STRpath); 363 Char **pv; 364 int hashval; 365 366 havhash = 1; 367 for (cnt = 0; cnt < sizeof xhash; cnt++) 368 xhash[cnt] = 0; 369 if (v == 0) 370 return; 371 for (pv = v->vec; *pv; pv++, i++) { 372 if (pv[0][0] != '/') 373 continue; 374 dirp = opendir(short2str(*pv)); 375 if (dirp == NULL) 376 continue; 377 while ((dp = readdir(dirp)) != NULL) { 378 if (dp->d_ino == 0) 379 continue; 380 if (dp->d_name[0] == '.' && 381 (dp->d_name[1] == '\0' || 382 dp->d_name[1] == '.' && dp->d_name[2] == '\0')) 383 continue; 384 hashval = hash(hashname(str2short(dp->d_name)), i); 385 bis(xhash, hashval); 386 /* tw_add_comm_name (dp->d_name); */ 387 } 388 (void) closedir(dirp); 389 } 390 } 391 392 void 393 dounhash() 394 { 395 havhash = 0; 396 } 397 398 void 399 hashstat() 400 { 401 if (hits + misses) 402 xprintf("%d hits, %d misses, %d%%\n", 403 hits, misses, 100 * hits / (hits + misses)); 404 } 405 406 /* 407 * Hash a command name. 408 */ 409 static int 410 hashname(cp) 411 register Char *cp; 412 { 413 register long h = 0; 414 415 while (*cp) 416 h = hash(h, *cp++); 417 return ((int) h); 418 } 419