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