1 static char *sccsid = "@(#)exec.c 4.1 10/09/80"; 2 3 #include "sh.h" 4 5 /* 6 * C shell 7 */ 8 9 /* 10 * System level search and execute of a command. 11 * We look in each directory for the specified command name. 12 * If the name contains a '/' then we execute only the full path name. 13 * If there is no search path then we execute only full path names. 14 */ 15 16 /* 17 * As we search for the command we note the first non-trivial error 18 * message for presentation to the user. This allows us often 19 * to show that a file has the wrong mode/no access when the file 20 * is not in the last component of the search path, so we must 21 * go on after first detecting the error. 22 */ 23 char *exerr; /* Execution error message */ 24 char *expath; /* Path for exerr */ 25 26 /* 27 * Xhash is an array of HSHSIZ chars, which are used to hash execs. 28 * If it is allocated, then to tell whether ``name'' is (possibly) 29 * present in the i'th component of the variable path, you look at 30 * the i'th bit of xhash[hash("name")]. This is setup automatically 31 * after .login is executed, and recomputed whenever ``path'' is 32 * changed. 33 */ 34 int havhash; 35 #define HSHSIZ 511 36 char xhash[HSHSIZ]; 37 #ifdef VFORK 38 int hits, misses; 39 #endif 40 41 /* Dummy search path for just absolute search when no path */ 42 char *justabs[] = { "", 0 }; 43 44 doexec(t) 45 register struct command *t; 46 { 47 char *sav; 48 register char *dp, **pv, **av; 49 register struct varent *v; 50 bool slash = any('/', t->t_dcom[0]); 51 int hashval, i; 52 char *blk[2]; 53 54 /* 55 * Glob the command name. If this does anything, then we 56 * will execute the command only relative to ".". One special 57 * case: if there is no PATH, then we execute only commands 58 * which start with '/'. 59 */ 60 dp = globone(t->t_dcom[0]); 61 sav = t->t_dcom[0]; 62 exerr = 0; expath = t->t_dcom[0] = dp; 63 xfree(sav); 64 v = adrof("path"); 65 if (v == 0 && expath[0] != '/') 66 pexerr(); 67 slash |= gflag; 68 69 /* 70 * Glob the argument list, if necessary. 71 * Otherwise trim off the quote bits. 72 */ 73 gflag = 0; av = &t->t_dcom[1]; 74 rscan(av, tglob); 75 if (gflag) { 76 av = glob(av); 77 if (av == 0) 78 error("No match"); 79 } 80 blk[0] = t->t_dcom[0]; 81 blk[1] = 0; 82 av = blkspl(blk, av); 83 #ifdef VFORK 84 Vav = av; 85 #endif 86 scan(av, trim); 87 88 xechoit(av); /* Echo command if -x */ 89 closech(); /* Close random fd's */ 90 91 /* 92 * We must do this after any possible forking (like `foo` 93 * in glob) so that this shell can still do subprocesses. 94 */ 95 sigsys(SIGCHLD, SIG_IGN); /* sigsys for vforks sake */ 96 97 /* 98 * If no path, no words in path, or a / in the filename 99 * then restrict the command search. 100 */ 101 if (v == 0 || v->vec[0] == 0 || slash) 102 pv = justabs; 103 else 104 pv = v->vec; 105 sav = strspl("/", *av); /* / command name for postpending */ 106 #ifdef VFORK 107 Vsav = sav; 108 #endif 109 if (havhash) 110 hashval = xhash[hash(*av)]; 111 i = 0; 112 #ifdef VFORK 113 hits++; 114 #endif 115 do { 116 if (!slash && pv[0][0] == '/' && havhash && (hashval & (1 << (i % 8))) == 0) 117 goto cont; 118 if (pv[0][0] == 0 || eq(pv[0], ".")) /* don't make ./xxx */ 119 texec(*av, av); 120 else { 121 dp = strspl(*pv, sav); 122 #ifdef VFORK 123 Vdp = dp; 124 #endif 125 texec(dp, av); 126 #ifdef VFORK 127 Vdp = 0; 128 #endif 129 xfree(dp); 130 } 131 #ifdef VFORK 132 misses++; 133 #endif 134 cont: 135 pv++; 136 i++; 137 } while (*pv); 138 #ifdef VFORK 139 hits--; 140 #endif 141 #ifdef VFORK 142 Vsav = 0; 143 Vav = 0; 144 #endif 145 xfree(sav); 146 xfree(av); 147 pexerr(); 148 } 149 150 pexerr() 151 { 152 153 /* Couldn't find the damn thing */ 154 setname(expath); 155 /* xfree(expath); */ 156 if (exerr) 157 bferr(exerr); 158 bferr("Command not found"); 159 } 160 161 /* Last resort shell */ 162 char *lastsh[] = { SHELLPATH, 0 }; 163 164 /* 165 * Execute command f, arg list t. 166 * Record error message if not found. 167 * Also do shell scripts here. 168 */ 169 texec(f, t) 170 char *f; 171 register char **t; 172 { 173 register struct varent *v; 174 register char **vp; 175 extern char *sys_errlist[]; 176 177 execv(f, t); 178 switch (errno) { 179 180 case ENOEXEC: 181 /* 182 * If there is an alias for shell, then 183 * put the words of the alias in front of the 184 * argument list replacing the command name. 185 * Note no interpretation of the words at this point. 186 */ 187 v = adrof1("shell", &aliases); 188 if (v == 0) { 189 #ifdef OTHERSH 190 register int ff = open(f, 0); 191 char ch; 192 #endif 193 194 vp = lastsh; 195 vp[0] = adrof("shell") ? value("shell") : SHELLPATH; 196 #ifdef OTHERSH 197 if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#') 198 vp[0] = OTHERSH; 199 close(ff); 200 #endif 201 } else 202 vp = v->vec; 203 t[0] = f; 204 t = blkspl(vp, t); /* Splice up the new arglst */ 205 f = *t; 206 execv(f, t); 207 xfree((char *)t); 208 /* The sky is falling, the sky is falling! */ 209 210 case ENOMEM: 211 Perror(f); 212 213 case ENOENT: 214 break; 215 216 default: 217 if (exerr == 0) { 218 exerr = sys_errlist[errno]; 219 expath = savestr(f); 220 } 221 } 222 } 223 224 execash(t, kp) 225 register struct command *kp; 226 { 227 228 didcch++; 229 signal(SIGINT, parintr); 230 signal(SIGQUIT, parintr); 231 signal(SIGTERM, parterm); /* if doexec loses, screw */ 232 lshift(kp->t_dcom, 1); 233 exiterr++; 234 doexec(kp); 235 /*NOTREACHED*/ 236 } 237 238 xechoit(t) 239 char **t; 240 { 241 242 if (adrof("echo")) { 243 flush(); 244 haderr = 1; 245 blkpr(t), printf("\n"); 246 haderr = 0; 247 } 248 } 249 250 dohash() 251 { 252 struct stat stb; 253 struct direct dirbuf[BUFSIZ / sizeof (struct direct)]; 254 char d_name[DIRSIZ + 1]; 255 register int dirf, cnt; 256 int i = 0; 257 struct varent *v = adrof("path"); 258 char **pv; 259 260 havhash = 1; 261 for (cnt = 0; cnt < HSHSIZ; cnt++) 262 xhash[cnt] = 0; 263 if (v == 0) 264 return; 265 for (pv = v->vec; *pv; pv++, i = (i + 1) % 8) { 266 if (pv[0][0] != '/') 267 continue; 268 dirf = open(*pv, 0); 269 if (dirf < 0) 270 continue; 271 if (fstat(dirf, &stb) < 0 || !isdir(stb)) { 272 close(dirf); 273 continue; 274 } 275 while ((cnt = read(dirf, (char *) dirbuf, sizeof dirbuf)) >= sizeof dirbuf[0]) { 276 register struct direct *ep = dirbuf; 277 278 for (cnt /= sizeof(struct direct); cnt > 0; cnt--, ep++) { 279 if (ep->d_ino == 0) 280 continue; 281 copdent(d_name, ep->d_name); 282 xhash[hash(d_name)] |= (1 << i); 283 } 284 } 285 close(dirf); 286 } 287 } 288 289 dounhash() 290 { 291 292 havhash = 0; 293 } 294 295 #ifdef VFORK 296 hashstat() 297 { 298 299 if (hits+misses) 300 printf("%d hits, %d misses, %2d%%\n", hits, misses, 100 * hits / (hits + misses)); 301 } 302 #endif 303 304 hash(cp) 305 register char *cp; 306 { 307 register long hash = 0; 308 int retval; 309 310 while (*cp) 311 hash += hash + *cp++; 312 if (hash < 0) 313 hash = -hash; 314 retval = hash % HSHSIZ; 315 return (retval); 316 } 317