|
|
1.1 root 1: static char *sccsid = "@(#)sh.exec.c 4.8 7/1/83";
2:
3: #include "sh.h"
4: #include <sys/dir.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: #ifdef notdef
97: sigsys(SIGCHLD, SIG_IGN); /* sigsys for vforks sake */
98: #endif
99: sigsetmask(0);
100:
101: /*
102: * If no path, no words in path, or a / in the filename
103: * then restrict the command search.
104: */
105: if (v == 0 || v->vec[0] == 0 || slash)
106: pv = justabs;
107: else
108: pv = v->vec;
109: sav = strspl("/", *av); /* / command name for postpending */
110: #ifdef VFORK
111: Vsav = sav;
112: #endif
113: if (havhash)
114: hashval = xhash[hash(*av)];
115: i = 0;
116: #ifdef VFORK
117: hits++;
118: #endif
119: do {
120: if (!slash && pv[0][0] == '/' && havhash && (hashval & (1 << (i % 8))) == 0)
121: goto cont;
122: if (pv[0][0] == 0 || eq(pv[0], ".")) /* don't make ./xxx */
123: texec(*av, av);
124: else {
125: dp = strspl(*pv, sav);
126: #ifdef VFORK
127: Vdp = dp;
128: #endif
129: texec(dp, av);
130: #ifdef VFORK
131: Vdp = 0;
132: #endif
133: xfree(dp);
134: }
135: #ifdef VFORK
136: misses++;
137: #endif
138: cont:
139: pv++;
140: i++;
141: } while (*pv);
142: #ifdef VFORK
143: hits--;
144: #endif
145: #ifdef VFORK
146: Vsav = 0;
147: Vav = 0;
148: #endif
149: xfree(sav);
150: xfree(av);
151: pexerr();
152: }
153:
154: pexerr()
155: {
156:
157: /* Couldn't find the damn thing */
158: setname(expath);
159: /* xfree(expath); */
160: if (exerr)
161: bferr(exerr);
162: bferr("Command not found");
163: }
164:
165: /* Last resort shell */
166: char *lastsh[] = { SHELLPATH, 0 };
167:
168: /*
169: * Execute command f, arg list t.
170: * Record error message if not found.
171: * Also do shell scripts here.
172: */
173: texec(f, t)
174: char *f;
175: register char **t;
176: {
177: register struct varent *v;
178: register char **vp;
179: extern char *sys_errlist[];
180:
181: execv(f, t);
182: switch (errno) {
183:
184: case ENOEXEC:
185: /*
186: * If there is an alias for shell, then
187: * put the words of the alias in front of the
188: * argument list replacing the command name.
189: * Note no interpretation of the words at this point.
190: */
191: v = adrof1("shell", &aliases);
192: if (v == 0) {
193: #ifdef OTHERSH
194: register int ff = open(f, 0);
195: char ch;
196: #endif
197:
198: vp = lastsh;
199: vp[0] = adrof("shell") ? value("shell") : SHELLPATH;
200: #ifdef OTHERSH
201: if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#')
202: vp[0] = OTHERSH;
203: close(ff);
204: #endif
205: } else
206: vp = v->vec;
207: t[0] = f;
208: t = blkspl(vp, t); /* Splice up the new arglst */
209: f = *t;
210: execv(f, t);
211: xfree((char *)t);
212: /* The sky is falling, the sky is falling! */
213:
214: case ENOMEM:
215: Perror(f);
216:
217: case ENOENT:
218: break;
219:
220: default:
221: if (exerr == 0) {
222: exerr = sys_errlist[errno];
223: expath = savestr(f);
224: }
225: }
226: }
227:
228: execash(t, kp)
229: register struct command *kp;
230: {
231:
232: didcch++;
233: rechist();
234: signal(SIGINT, parintr);
235: signal(SIGQUIT, parintr);
236: signal(SIGTERM, parterm); /* if doexec loses, screw */
237: lshift(kp->t_dcom, 1);
238: exiterr++;
239: doexec(kp);
240: /*NOTREACHED*/
241: }
242:
243: xechoit(t)
244: char **t;
245: {
246:
247: if (adrof("echo")) {
248: flush();
249: haderr = 1;
250: blkpr(t), printf("\n");
251: haderr = 0;
252: }
253: }
254:
255: dohash()
256: {
257: struct stat stb;
258: DIR *dirp;
259: register struct direct *dp;
260: register int cnt;
261: int i = 0;
262: struct varent *v = adrof("path");
263: char **pv;
264:
265: havhash = 1;
266: for (cnt = 0; cnt < HSHSIZ; cnt++)
267: xhash[cnt] = 0;
268: if (v == 0)
269: return;
270: for (pv = v->vec; *pv; pv++, i = (i + 1) % 8) {
271: if (pv[0][0] != '/')
272: continue;
273: dirp = opendir(*pv);
274: if (dirp == NULL)
275: continue;
276: if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
277: closedir(dirp);
278: continue;
279: }
280: while ((dp = readdir(dirp)) != NULL) {
281: if (dp->d_ino == 0)
282: continue;
283: xhash[hash(dp->d_name)] |= (1 << i);
284: }
285: closedir(dirp);
286: }
287: }
288:
289: dounhash()
290: {
291:
292: havhash = 0;
293: }
294:
295: #ifdef VFORK
296: hashstat()
297: {
298:
299: if (hits+misses)
300: printf("%d hits, %d misses, %2d%%\n", hits, misses, 100 * hits / (hits + misses));
301: }
302: #endif
303:
304: hash(cp)
305: register char *cp;
306: {
307: register long hash = 0;
308: int retval;
309:
310: while (*cp)
311: hash += hash + *cp++;
312: if (hash < 0)
313: hash = -hash;
314: retval = hash % HSHSIZ;
315: return (retval);
316: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.