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