1 static char *sccsid = "@(#)exec.c 4.4 05/07/82"; 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 sigsys(SIGCHLD, SIG_IGN); /* sigsys for vforks sake */ 97 98 /* 99 * If no path, no words in path, or a / in the filename 100 * then restrict the command search. 101 */ 102 if (v == 0 || v->vec[0] == 0 || slash) 103 pv = justabs; 104 else 105 pv = v->vec; 106 sav = strspl("/", *av); /* / command name for postpending */ 107 #ifdef VFORK 108 Vsav = sav; 109 #endif 110 if (havhash) 111 hashval = xhash[hash(*av)]; 112 i = 0; 113 #ifdef VFORK 114 hits++; 115 #endif 116 do { 117 if (!slash && pv[0][0] == '/' && havhash && (hashval & (1 << (i % 8))) == 0) 118 goto cont; 119 if (pv[0][0] == 0 || eq(pv[0], ".")) /* don't make ./xxx */ 120 texec(*av, av); 121 else { 122 dp = strspl(*pv, sav); 123 #ifdef VFORK 124 Vdp = dp; 125 #endif 126 texec(dp, av); 127 #ifdef VFORK 128 Vdp = 0; 129 #endif 130 xfree(dp); 131 } 132 #ifdef VFORK 133 misses++; 134 #endif 135 cont: 136 pv++; 137 i++; 138 } while (*pv); 139 #ifdef VFORK 140 hits--; 141 #endif 142 #ifdef VFORK 143 Vsav = 0; 144 Vav = 0; 145 #endif 146 xfree(sav); 147 xfree(av); 148 pexerr(); 149 } 150 151 pexerr() 152 { 153 154 /* Couldn't find the damn thing */ 155 setname(expath); 156 /* xfree(expath); */ 157 if (exerr) 158 bferr(exerr); 159 bferr("Command not found"); 160 } 161 162 /* Last resort shell */ 163 char *lastsh[] = { SHELLPATH, 0 }; 164 165 /* 166 * Execute command f, arg list t. 167 * Record error message if not found. 168 * Also do shell scripts here. 169 */ 170 texec(f, t) 171 char *f; 172 register char **t; 173 { 174 register struct varent *v; 175 register char **vp; 176 extern char *sys_errlist[]; 177 178 execv(f, t); 179 switch (errno) { 180 181 case ENOEXEC: 182 /* 183 * If there is an alias for shell, then 184 * put the words of the alias in front of the 185 * argument list replacing the command name. 186 * Note no interpretation of the words at this point. 187 */ 188 v = adrof1("shell", &aliases); 189 if (v == 0) { 190 #ifdef OTHERSH 191 register int ff = open(f, 0); 192 char ch; 193 #endif 194 195 vp = lastsh; 196 vp[0] = adrof("shell") ? value("shell") : SHELLPATH; 197 #ifdef OTHERSH 198 if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#') 199 vp[0] = OTHERSH; 200 close(ff); 201 #endif 202 } else 203 vp = v->vec; 204 t[0] = f; 205 t = blkspl(vp, t); /* Splice up the new arglst */ 206 f = *t; 207 execv(f, t); 208 xfree((char *)t); 209 /* The sky is falling, the sky is falling! */ 210 211 case ENOMEM: 212 Perror(f); 213 214 case ENOENT: 215 break; 216 217 default: 218 if (exerr == 0) { 219 exerr = sys_errlist[errno]; 220 expath = savestr(f); 221 } 222 } 223 } 224 225 execash(t, kp) 226 register struct command *kp; 227 { 228 229 didcch++; 230 rechist(); 231 signal(SIGINT, parintr); 232 signal(SIGQUIT, parintr); 233 signal(SIGTERM, parterm); /* if doexec loses, screw */ 234 lshift(kp->t_dcom, 1); 235 exiterr++; 236 doexec(kp); 237 /*NOTREACHED*/ 238 } 239 240 xechoit(t) 241 char **t; 242 { 243 244 if (adrof("echo")) { 245 flush(); 246 haderr = 1; 247 blkpr(t), printf("\n"); 248 haderr = 0; 249 } 250 } 251 252 dohash() 253 { 254 struct stat stb; 255 DIR *dirp; 256 register struct direct *dp; 257 register int cnt; 258 int i = 0; 259 struct varent *v = adrof("path"); 260 char **pv; 261 262 havhash = 1; 263 for (cnt = 0; cnt < HSHSIZ; cnt++) 264 xhash[cnt] = 0; 265 if (v == 0) 266 return; 267 for (pv = v->vec; *pv; pv++, i = (i + 1) % 8) { 268 if (pv[0][0] != '/') 269 continue; 270 dirp = opendir(*pv); 271 if (dirp == NULL) 272 continue; 273 if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) { 274 closedir(dirp); 275 continue; 276 } 277 while ((dp = readdir(dirp)) != NULL) { 278 if (dp->d_ino == 0) 279 continue; 280 xhash[hash(dp->d_name)] |= (1 << i); 281 } 282 closedir(dirp); 283 } 284 } 285 286 dounhash() 287 { 288 289 havhash = 0; 290 } 291 292 #ifdef VFORK 293 hashstat() 294 { 295 296 if (hits+misses) 297 printf("%d hits, %d misses, %2d%%\n", hits, misses, 100 * hits / (hits + misses)); 298 } 299 #endif 300 301 hash(cp) 302 register char *cp; 303 { 304 register long hash = 0; 305 int retval; 306 307 while (*cp) 308 hash += hash + *cp++; 309 if (hash < 0) 310 hash = -hash; 311 retval = hash % HSHSIZ; 312 return (retval); 313 } 314