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