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