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