|
|
1.1 root 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 = any('/', 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 = glob(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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.