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