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 = "@(#)sh.exec.c 5.7 (Berkeley) 5/27/90"; 9 #endif 10 11 #include "sh.h" 12 #include <sys/dir.h> 13 #include <string.h> 14 #include "pathnames.h" 15 16 /* 17 * C shell 18 */ 19 20 /* 21 * System level search and execute of a command. 22 * We look in each directory for the specified command name. 23 * If the name contains a '/' then we execute only the full path name. 24 * If there is no search path then we execute only full path names. 25 */ 26 27 /* 28 * As we search for the command we note the first non-trivial error 29 * message for presentation to the user. This allows us often 30 * to show that a file has the wrong mode/no access when the file 31 * is not in the last component of the search path, so we must 32 * go on after first detecting the error. 33 */ 34 char *exerr; /* Execution error message */ 35 char *expath; /* Path for exerr */ 36 37 /* 38 * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 39 * to hash execs. If it is allocated (havhash true), then to tell 40 * whether ``name'' is (possibly) present in the i'th component 41 * of the variable path, you look at the bit in xhash indexed by 42 * hash(hashname("name"), i). This is setup automatically 43 * after .login is executed, and recomputed whenever ``path'' is 44 * changed. 45 * The two part hash function is designed to let texec() call the 46 * more expensive hashname() only once and the simple hash() several 47 * times (once for each path component checked). 48 * Byte size is assumed to be 8. 49 */ 50 #define HSHSIZ 8192 /* 1k bytes */ 51 #define HSHMASK (HSHSIZ - 1) 52 #define HSHMUL 243 53 char xhash[HSHSIZ / 8]; 54 #define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK) 55 #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 56 #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 57 #ifdef VFORK 58 int hits, misses; 59 #endif 60 61 /* Dummy search path for just absolute search when no path */ 62 char *justabs[] = { "", 0 }; 63 64 doexec(t) 65 register struct command *t; 66 { 67 char *sav; 68 register char *dp, **pv, **av; 69 register struct varent *v; 70 bool slash = (bool)index(t->t_dcom[0], '/'); 71 int hashval, hashval1, i; 72 char *blk[2]; 73 74 /* 75 * Glob the command name. If this does anything, then we 76 * will execute the command only relative to ".". One special 77 * case: if there is no PATH, then we execute only commands 78 * which start with '/'. 79 */ 80 dp = globone(t->t_dcom[0]); 81 sav = t->t_dcom[0]; 82 exerr = 0; expath = t->t_dcom[0] = dp; 83 xfree(sav); 84 v = adrof("path"); 85 if (v == 0 && expath[0] != '/') 86 pexerr(); 87 slash |= gflag; 88 89 /* 90 * Glob the argument list, if necessary. 91 * Otherwise trim off the quote bits. 92 */ 93 gflag = 0; av = &t->t_dcom[1]; 94 tglob(av); 95 if (gflag) { 96 av = globall(av); 97 if (av == 0) 98 error("No match"); 99 } 100 blk[0] = t->t_dcom[0]; 101 blk[1] = 0; 102 av = blkspl(blk, av); 103 #ifdef VFORK 104 Vav = av; 105 #endif 106 trim(av); 107 108 xechoit(av); /* Echo command if -x */ 109 /* 110 * Since all internal file descriptors are set to close on exec, 111 * we don't need to close them explicitly here. Just reorient 112 * ourselves for error messages. 113 */ 114 SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0; 115 116 /* 117 * We must do this AFTER any possible forking (like `foo` 118 * in glob) so that this shell can still do subprocesses. 119 */ 120 (void) sigsetmask(0L); 121 122 /* 123 * If no path, no words in path, or a / in the filename 124 * then restrict the command search. 125 */ 126 if (v == 0 || v->vec[0] == 0 || slash) 127 pv = justabs; 128 else 129 pv = v->vec; 130 sav = strspl("/", *av); /* / command name for postpending */ 131 #ifdef VFORK 132 Vsav = sav; 133 #endif 134 if (havhash) 135 hashval = hashname(*av); 136 i = 0; 137 #ifdef VFORK 138 hits++; 139 #endif 140 do { 141 if (!slash && pv[0][0] == '/' && havhash) { 142 hashval1 = hash(hashval, i); 143 if (!bit(xhash, hashval1)) 144 goto cont; 145 } 146 if (pv[0][0] == 0 || eq(pv[0], ".")) /* don't make ./xxx */ 147 texec(*av, av); 148 else { 149 dp = strspl(*pv, sav); 150 #ifdef VFORK 151 Vdp = dp; 152 #endif 153 texec(dp, av); 154 #ifdef VFORK 155 Vdp = 0; 156 #endif 157 xfree(dp); 158 } 159 #ifdef VFORK 160 misses++; 161 #endif 162 cont: 163 pv++; 164 i++; 165 } while (*pv); 166 #ifdef VFORK 167 hits--; 168 #endif 169 #ifdef VFORK 170 Vsav = 0; 171 Vav = 0; 172 #endif 173 xfree(sav); 174 xfree((char *)av); 175 pexerr(); 176 } 177 178 pexerr() 179 { 180 181 /* Couldn't find the damn thing */ 182 setname(expath); 183 /* xfree(expath); */ 184 if (exerr) 185 bferr(exerr); 186 bferr("Command not found"); 187 } 188 189 /* 190 * Execute command f, arg list t. 191 * Record error message if not found. 192 * Also do shell scripts here. 193 */ 194 texec(f, t) 195 char *f; 196 register char **t; 197 { 198 register struct varent *v; 199 register char **vp; 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 = strerror(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