|
|
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.2 (Berkeley) 6/6/85";
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(0);
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(v)
279: char **v;
280: {
281: struct stat stb;
282: DIR *dirp;
283: register struct direct *dp;
284: register int cnt;
285: int i = 0;
286: struct varent *v = adrof("path");
287: char **pv;
288: int hashval;
289:
290: havhash = 1;
291: for (cnt = 0; cnt < sizeof xhash; cnt++)
292: xhash[cnt] = 0;
293: if (v == 0)
294: return;
295: for (pv = v->vec; *pv; pv++, i++) {
296: if (pv[0][0] != '/')
297: continue;
298: dirp = opendir(*pv);
299: if (dirp == NULL)
300: continue;
301: if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
302: closedir(dirp);
303: continue;
304: }
305: while ((dp = readdir(dirp)) != NULL) {
306: if (dp->d_ino == 0)
307: continue;
308: if (dp->d_name[0] == '.' &&
309: (dp->d_name[1] == '\0' ||
310: dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
311: continue;
312: hashval = hash(hashname(dp->d_name), i);
313: bis(xhash, hashval);
314: }
315: closedir(dirp);
316: }
317: }
318:
319: dounhash()
320: {
321:
322: havhash = 0;
323: }
324:
325: #ifdef VFORK
326: hashstat()
327: {
328:
329: if (hits+misses)
330: printf("%d hits, %d misses, %d%%\n",
331: hits, misses, 100 * hits / (hits + misses));
332: }
333: #endif
334:
335: /*
336: * Hash a command name.
337: */
338: hashname(cp)
339: register char *cp;
340: {
341: register long h = 0;
342:
343: while (*cp)
344: h = hash(h, *cp++);
345: return ((int) h);
346: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.