1 /*
2 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
6 /* All Rights Reserved */
7
8 /*
9 * Copyright (c) 1980 Regents of the University of California.
10 * All rights reserved. The Berkeley Software License Agreement
11 * specifies the terms and conditions for redistribution.
12 */
13
14 #include "sh.h"
15 #include <dirent.h>
16 #include <string.h>
17 #include "sh.tconst.h"
18
19
20 /*
21 * C shell
22 */
23
24 /*
25 * System level search and execute of a command.
26 * We look in each directory for the specified command name.
27 * If the name contains a '/' then we execute only the full path name.
28 * If there is no search path then we execute only full path names.
29 */
30
31 char xhash[HSHSIZ / 8];
32 tchar **Vav;
33 tchar *Vdp;
34 tchar *Vsav;
35
36 struct varent aliases;
37 bool havhash;
38 static int hits;
39 static int misses;
40 short SHOUT;
41 short SHIN;
42
43 void (*parintr)();
44 void (*parterm)();
45
46 /*
47 * As we search for the command we note the first non-trivial error
48 * message for presentation to the user. This allows us often
49 * to show that a file has the wrong mode/no access when the file
50 * is not in the last component of the search path, so we must
51 * go on after first detecting the error.
52 */
53 char *exerr; /* Execution error message */
54
55 void pexerr(void);
56 void texec(struct command *, tchar *, tchar **);
57 void xechoit(tchar **);
58 void dohash(char []);
59
60 static void tconvert(struct command *, tchar *, tchar **);
61
62
63 extern DIR *opendir_(tchar *);
64
65 void
doexec(struct command * t)66 doexec(struct command *t)
67 {
68 tchar *sav;
69 tchar *dp, **pv, **av;
70 struct varent *v;
71 bool slash;
72 int hashval, hashval1, i;
73 tchar *blk[2];
74 #ifdef TRACE
75 tprintf("TRACE- doexec()\n");
76 #endif
77
78 /*
79 * Glob the command name. If this does anything, then we
80 * will execute the command only relative to ".". One special
81 * case: if there is no PATH, then we execute only commands
82 * which start with '/'.
83 */
84 dp = globone(t->t_dcom[0]);
85 sav = t->t_dcom[0];
86 exerr = 0; t->t_dcom[0] = dp;
87 setname(dp);
88 xfree(sav);
89 v = adrof(S_path /* "path" */);
90 if (v == 0 && dp[0] != '/') {
91 pexerr();
92 }
93 slash = gflag;
94
95 /*
96 * Glob the argument list, if necessary.
97 * Otherwise trim off the quote bits.
98 */
99 gflag = 0; av = &t->t_dcom[1];
100 tglob(av);
101 if (gflag) {
102 av = glob(av);
103 if (av == 0)
104 error("No match");
105 }
106 blk[0] = t->t_dcom[0];
107 blk[1] = 0;
108 av = blkspl(blk, av);
109 #ifdef VFORK
110 Vav = av;
111 #endif
112 trim(av);
113 slash |= any('/', av[0]);
114
115 xechoit(av); /* Echo command if -x */
116 /*
117 * Since all internal file descriptors are set to close on exec,
118 * we don't need to close them explicitly here. Just reorient
119 * ourselves for error messages.
120 */
121 SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0;
122
123 /*
124 * We must do this AFTER any possible forking (like `foo`
125 * in glob) so that this shell can still do subprocesses.
126 */
127 (void) sigsetmask(0);
128
129 /*
130 * If no path, no words in path, or a / in the filename
131 * then restrict the command search.
132 */
133 if (v == 0 || v->vec[0] == 0 || slash)
134 pv = justabs;
135 else
136 pv = v->vec;
137 /* / command name for postpending */
138 sav = strspl(S_SLASH /* "/" */, *av);
139 #ifdef VFORK
140 Vsav = sav;
141 #endif
142 if (havhash)
143 hashval = hashname(*av);
144 i = 0;
145 #ifdef VFORK
146 hits++;
147 #endif
148 do {
149 if (!slash && pv[0][0] == '/' && havhash) {
150 hashval1 = hash(hashval, i);
151 if (!bit(xhash, hashval1))
152 goto cont;
153 }
154
155 /* don't make ./xxx */
156 if (pv[0][0] == 0 || eq(pv[0], S_DOT /* "." */)) {
157 texec(t, *av, av);
158 } else {
159 dp = strspl(*pv, sav);
160 #ifdef VFORK
161 Vdp = dp;
162 #endif
163 texec(t, dp, av);
164 #ifdef VFORK
165 Vdp = 0;
166 #endif
167 xfree(dp);
168 }
169 #ifdef VFORK
170 misses++;
171 #endif
172 cont:
173 pv++;
174 i++;
175 } while (*pv);
176 #ifdef VFORK
177 hits--;
178 #endif
179 #ifdef VFORK
180 Vsav = 0;
181 Vav = 0;
182 #endif
183 xfree(sav);
184 xfree((char *)av);
185 pexerr();
186 }
187
188 void
pexerr(void)189 pexerr(void)
190 {
191
192 #ifdef TRACE
193 tprintf("TRACE- pexerr()\n");
194 #endif
195 /* Couldn't find the damn thing */
196 if (exerr)
197 bferr(exerr);
198 bferr("Command not found");
199 }
200
201 /*
202 * Execute command f, arg list t.
203 * Record error message if not found.
204 * Also do shell scripts here.
205 */
206 void
texec(struct command * cmd,tchar * f,tchar ** t)207 texec(struct command *cmd, tchar *f, tchar **t)
208 {
209 struct varent *v;
210 tchar **vp;
211 tchar *lastsh[2];
212
213 #ifdef TRACE
214 tprintf("TRACE- texec()\n");
215 #endif
216 /* convert cfname and cargs from tchar to char */
217 tconvert(cmd, f, t);
218
219 execv(cmd->cfname, cmd->cargs);
220
221 /*
222 * exec returned, free up allocations from above
223 * tconvert(), zero cfname and cargs to prevent
224 * duplicate free() in freesyn()
225 */
226 xfree(cmd->cfname);
227 chr_blkfree(cmd->cargs);
228 cmd->cfname = (char *)0;
229 cmd->cargs = (char **)0;
230
231 switch (errno) {
232 case ENOEXEC:
233 /* check that this is not a binary file */
234 {
235 int ff = open_(f, 0);
236 tchar ch[MB_LEN_MAX];
237
238 if (ff != -1 && read_(ff, ch, 1) == 1 &&
239 !isprint(ch[0]) && !isspace(ch[0])) {
240 printf("Cannot execute binary file.\n");
241 Perror(f);
242 (void) close(ff);
243 unsetfd(ff);
244 return;
245 }
246 (void) close(ff);
247 unsetfd(ff);
248 }
249 /*
250 * If there is an alias for shell, then
251 * put the words of the alias in front of the
252 * argument list replacing the command name.
253 * Note no interpretation of the words at this point.
254 */
255 v = adrof1(S_shell /* "shell" */, &aliases);
256 if (v == 0) {
257 #ifdef OTHERSH
258 int ff = open_(f, 0);
259 tchar ch[MB_LEN_MAX];
260 #endif
261
262 vp = lastsh;
263 vp[0] = adrof(S_shell /* "shell" */) ?
264 value(S_shell /* "shell" */) :
265 S_SHELLPATH /* SHELLPATH */;
266 vp[1] = (tchar *) NULL;
267 #ifdef OTHERSH
268 if (ff != -1 && read_(ff, ch, 1) == 1 && ch[0] != '#')
269 vp[0] = S_OTHERSH /* OTHERSH */;
270 (void) close(ff);
271 unsetfd(ff);
272 #endif
273 } else
274 vp = v->vec;
275 t[0] = f;
276 t = blkspl(vp, t); /* Splice up the new arglst */
277 f = *t;
278
279 tconvert(cmd, f, t); /* convert tchar to char */
280
281 /*
282 * now done with tchar arg list t,
283 * free the space calloc'd by above blkspl()
284 */
285 xfree((char *)t);
286
287 execv(cmd->cfname, cmd->cargs); /* exec the command */
288
289 /* exec returned, same free'ing as above */
290 xfree(cmd->cfname);
291 chr_blkfree(cmd->cargs);
292 cmd->cfname = (char *)0;
293 cmd->cargs = (char **)0;
294
295 /* The sky is falling, the sky is falling! */
296
297 case ENOMEM:
298 Perror(f);
299
300 case ENOENT:
301 break;
302
303 default:
304 if (exerr == 0) {
305 exerr = strerror(errno);
306 setname(f);
307 }
308 }
309 }
310
311
312 static void
tconvert(struct command * cmd,tchar * fname,tchar ** list)313 tconvert(struct command *cmd, tchar *fname, tchar **list)
314 {
315 char **rc;
316 int len;
317
318 cmd->cfname = tstostr(NULL, fname);
319
320 len = blklen(list);
321 rc = cmd->cargs = (char **)
322 xcalloc((uint_t)(len + 1), sizeof (char **));
323 while (len--)
324 *rc++ = tstostr(NULL, *list++);
325 *rc = NULL;
326 }
327
328
329 /*ARGSUSED*/
330 void
execash(tchar ** t,struct command * kp)331 execash(tchar **t, struct command *kp)
332 {
333 #ifdef TRACE
334 tprintf("TRACE- execash()\n");
335 #endif
336
337 rechist();
338 (void) signal(SIGINT, parintr);
339 (void) signal(SIGQUIT, parintr);
340 (void) signal(SIGTERM, parterm); /* if doexec loses, screw */
341 lshift(kp->t_dcom, 1);
342 exiterr++;
343 doexec(kp);
344 /*NOTREACHED*/
345 }
346
347 void
xechoit(tchar ** t)348 xechoit(tchar **t)
349 {
350 #ifdef TRACE
351 tprintf("TRACE- xechoit()\n");
352 #endif
353
354 if (adrof(S_echo /* "echo" */)) {
355 flush();
356 haderr = 1;
357 blkpr(t), Putchar('\n');
358 haderr = 0;
359 }
360 }
361
362 /*
363 * This routine called when user enters "rehash".
364 * Both the path and cdpath caching arrays will
365 * be rehashed, via calling dohash. If either
366 * variable is not set with a value, then dohash
367 * just exits.
368 */
369 void
dorehash(void)370 dorehash(void)
371 {
372 dohash(xhash);
373 dohash(xhash2);
374 }
375
376 /*
377 * Fill up caching arrays for path and cdpath
378 */
379 void
dohash(char cachearray[])380 dohash(char cachearray[])
381 {
382 struct stat stb;
383 DIR *dirp;
384 struct dirent *dp;
385 int cnt;
386 int i = 0;
387 struct varent *v;
388 tchar **pv;
389 int hashval;
390 tchar curdir_[MAXNAMLEN+1];
391
392 #ifdef TRACE
393 tprintf("TRACE- dohash()\n");
394 #endif
395 /* Caching $path */
396 if (cachearray == xhash) {
397 havhash = 1;
398 v = adrof(S_path /* "path" */);
399 } else { /* Caching $cdpath */
400 havhash2 = 1;
401 v = adrof(S_cdpath /* "cdpath" */);
402 }
403
404 for (cnt = 0; cnt < (HSHSIZ / 8); cnt++)
405 cachearray[cnt] = 0;
406 if (v == 0)
407 return;
408 for (pv = v->vec; *pv; pv++, i++) {
409 if (pv[0][0] != '/')
410 continue;
411 dirp = opendir_(*pv);
412 if (dirp == NULL)
413 continue;
414 if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
415 unsetfd(dirp->dd_fd);
416 closedir_(dirp);
417 continue;
418 }
419 while ((dp = readdir(dirp)) != NULL) {
420 if (dp->d_ino == 0)
421 continue;
422 if (dp->d_name[0] == '.' &&
423 (dp->d_name[1] == '\0' ||
424 dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
425 continue;
426 hashval = hash(hashname(strtots(curdir_, dp->d_name)),
427 i);
428 bis(cachearray, hashval);
429 }
430 unsetfd(dirp->dd_fd);
431 closedir_(dirp);
432 }
433 }
434
435 void
dounhash(void)436 dounhash(void)
437 {
438
439 #ifdef TRACE
440 tprintf("TRACE- dounhash()\n");
441 #endif
442 havhash = 0;
443 havhash2 = 0;
444 }
445
446 #ifdef VFORK
447 void
hashstat(void)448 hashstat(void)
449 {
450 #ifdef TRACE
451 tprintf("TRACE- hashstat_()\n");
452 #endif
453
454 if (hits+misses)
455 printf("%d hits, %d misses, %d%%\n",
456 hits, misses, 100 * hits / (hits + misses));
457 }
458 #endif
459
460 /*
461 * Hash a command name.
462 */
463 int
hashname(tchar * cp)464 hashname(tchar *cp)
465 {
466 long h = 0;
467
468 #ifdef TRACE
469 tprintf("TRACE- hashname()\n");
470 #endif
471 while (*cp)
472 h = hash(h, *cp++);
473 return ((int)h);
474 }
475