exec.c revision 1.5 1 /*-
2 * Copyright (c) 1980, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 /*static char sccsid[] = "from: @(#)exec.c 8.1 (Berkeley) 5/31/93";*/
36 static char *rcsid = "$Id: exec.c,v 1.5 1994/09/21 00:10:48 mycroft Exp $";
37 #endif /* not lint */
38
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <dirent.h>
42 #include <fcntl.h>
43 #include <sys/stat.h>
44 #include <errno.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #if __STDC__
49 # include <stdarg.h>
50 #else
51 # include <varargs.h>
52 #endif
53
54 #include "csh.h"
55 #include "extern.h"
56
57 /*
58 * System level search and execute of a command. We look in each directory
59 * for the specified command name. If the name contains a '/' then we
60 * execute only the full path name. If there is no search path then we
61 * execute only full path names.
62 */
63 extern char **environ;
64
65 /*
66 * As we search for the command we note the first non-trivial error
67 * message for presentation to the user. This allows us often
68 * to show that a file has the wrong mode/no access when the file
69 * is not in the last component of the search path, so we must
70 * go on after first detecting the error.
71 */
72 static char *exerr; /* Execution error message */
73 static Char *expath; /* Path for exerr */
74
75 /*
76 * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
77 * to hash execs. If it is allocated (havhash true), then to tell
78 * whether ``name'' is (possibly) present in the i'th component
79 * of the variable path, you look at the bit in xhash indexed by
80 * hash(hashname("name"), i). This is setup automatically
81 * after .login is executed, and recomputed whenever ``path'' is
82 * changed.
83 * The two part hash function is designed to let texec() call the
84 * more expensive hashname() only once and the simple hash() several
85 * times (once for each path component checked).
86 * Byte size is assumed to be 8.
87 */
88 #define HSHSIZ 8192 /* 1k bytes */
89 #define HSHMASK (HSHSIZ - 1)
90 #define HSHMUL 243
91 static char xhash[HSHSIZ / 8];
92
93 #define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK)
94 #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
95 #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */
96 static int hits, misses;
97
98 /* Dummy search path for just absolute search when no path */
99 static Char *justabs[] = {STRNULL, 0};
100
101 static void pexerr __P((void));
102 static void texec __P((Char *, Char **));
103 static int hashname __P((Char *));
104 static void tellmewhat __P((struct wordent *));
105 static int executable __P((Char *, Char *, bool));
106 static int iscommand __P((Char *));
107
108
109 void
110 /*ARGSUSED*/
111 doexec(v, t)
112 Char **v;
113 struct command *t;
114 {
115 register Char *dp, **pv, **av, *sav;
116 register struct varent *pathv;
117 register bool slash;
118 register int hashval = 0, hashval1, i;
119 Char *blk[2];
120
121 /*
122 * Glob the command name. We will search $path even if this does something,
123 * as in sh but not in csh. One special case: if there is no PATH, then we
124 * execute only commands which start with '/'.
125 */
126 blk[0] = t->t_dcom[0];
127 blk[1] = 0;
128 gflag = 0, tglob(blk);
129 if (gflag) {
130 pv = globall(blk);
131 if (pv == 0) {
132 setname(vis_str(blk[0]));
133 stderror(ERR_NAME | ERR_NOMATCH);
134 }
135 gargv = 0;
136 }
137 else
138 pv = saveblk(blk);
139
140 trim(pv);
141
142 exerr = 0;
143 expath = Strsave(pv[0]);
144 Vexpath = expath;
145
146 pathv = adrof(STRpath);
147 if (pathv == 0 && expath[0] != '/') {
148 blkfree(pv);
149 pexerr();
150 }
151 slash = any(short2str(expath), '/');
152
153 /*
154 * Glob the argument list, if necessary. Otherwise trim off the quote bits.
155 */
156 gflag = 0;
157 av = &t->t_dcom[1];
158 tglob(av);
159 if (gflag) {
160 av = globall(av);
161 if (av == 0) {
162 blkfree(pv);
163 setname(vis_str(expath));
164 stderror(ERR_NAME | ERR_NOMATCH);
165 }
166 gargv = 0;
167 }
168 else
169 av = saveblk(av);
170
171 blkfree(t->t_dcom);
172 t->t_dcom = blkspl(pv, av);
173 xfree((ptr_t) pv);
174 xfree((ptr_t) av);
175 av = t->t_dcom;
176 trim(av);
177
178 if (*av == NULL || **av == '\0')
179 pexerr();
180
181 xechoit(av); /* Echo command if -x */
182 /*
183 * Since all internal file descriptors are set to close on exec, we don't
184 * need to close them explicitly here. Just reorient ourselves for error
185 * messages.
186 */
187 SHIN = 0;
188 SHOUT = 1;
189 SHERR = 2;
190 OLDSTD = 0;
191 /*
192 * We must do this AFTER any possible forking (like `foo` in glob) so that
193 * this shell can still do subprocesses.
194 */
195 (void) sigsetmask((sigset_t) 0);
196 /*
197 * If no path, no words in path, or a / in the filename then restrict the
198 * command search.
199 */
200 if (pathv == 0 || pathv->vec[0] == 0 || slash)
201 pv = justabs;
202 else
203 pv = pathv->vec;
204 sav = Strspl(STRslash, *av);/* / command name for postpending */
205 Vsav = sav;
206 if (havhash)
207 hashval = hashname(*av);
208 i = 0;
209 hits++;
210 do {
211 /*
212 * Try to save time by looking at the hash table for where this command
213 * could be. If we are doing delayed hashing, then we put the names in
214 * one at a time, as the user enters them. This is kinda like Korn
215 * Shell's "tracked aliases".
216 */
217 if (!slash && pv[0][0] == '/' && havhash) {
218 hashval1 = hash(hashval, i);
219 if (!bit(xhash, hashval1))
220 goto cont;
221 }
222 if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */
223 texec(*av, av);
224 else {
225 dp = Strspl(*pv, sav);
226 Vdp = dp;
227 texec(dp, av);
228 Vdp = 0;
229 xfree((ptr_t) dp);
230 }
231 misses++;
232 cont:
233 pv++;
234 i++;
235 } while (*pv);
236 hits--;
237 Vsav = 0;
238 xfree((ptr_t) sav);
239 pexerr();
240 }
241
242 static void
243 pexerr()
244 {
245 /* Couldn't find the damn thing */
246 if (expath) {
247 setname(vis_str(expath));
248 Vexpath = 0;
249 xfree((ptr_t) expath);
250 expath = 0;
251 }
252 else
253 setname("");
254 if (exerr)
255 stderror(ERR_NAME | ERR_STRING, exerr);
256 stderror(ERR_NAME | ERR_COMMAND);
257 }
258
259 /*
260 * Execute command f, arg list t.
261 * Record error message if not found.
262 * Also do shell scripts here.
263 */
264 static void
265 texec(sf, st)
266 Char *sf;
267 register Char **st;
268 {
269 register char **t;
270 register char *f;
271 register struct varent *v;
272 register Char **vp;
273 Char *lastsh[2];
274 int fd;
275 unsigned char c;
276 Char *st0, **ost;
277
278 /* The order for the conversions is significant */
279 t = short2blk(st);
280 f = short2str(sf);
281 Vt = t;
282 errno = 0; /* don't use a previous error */
283 (void) execve(f, t, environ);
284 Vt = 0;
285 blkfree((Char **) t);
286 switch (errno) {
287
288 case ENOEXEC:
289 /*
290 * From: casper (at) fwi.uva.nl (Casper H.S. Dik) If we could not execute
291 * it, don't feed it to the shell if it looks like a binary!
292 */
293 if ((fd = open(f, O_RDONLY)) != -1) {
294 if (read(fd, (char *) &c, 1) == 1) {
295 if (!Isprint(c) && (c != '\n' && c != '\t')) {
296 (void) close(fd);
297 /*
298 * We *know* what ENOEXEC means.
299 */
300 stderror(ERR_ARCH, f, strerror(errno));
301 }
302 }
303 #ifdef _PATH_BSHELL
304 else
305 c = '#';
306 #endif
307 (void) close(fd);
308 }
309 /*
310 * If there is an alias for shell, then put the words of the alias in
311 * front of the argument list replacing the command name. Note no
312 * interpretation of the words at this point.
313 */
314 v = adrof1(STRshell, &aliases);
315 if (v == 0) {
316 vp = lastsh;
317 vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH;
318 vp[1] = NULL;
319 #ifdef _PATH_BSHELL
320 if (fd != -1 && c != '#')
321 vp[0] = STR_BSHELL;
322 #endif
323 }
324 else
325 vp = v->vec;
326 st0 = st[0];
327 st[0] = sf;
328 ost = st;
329 st = blkspl(vp, st); /* Splice up the new arglst */
330 ost[0] = st0;
331 sf = *st;
332 /* The order for the conversions is significant */
333 t = short2blk(st);
334 f = short2str(sf);
335 xfree((ptr_t) st);
336 Vt = t;
337 (void) execve(f, t, environ);
338 Vt = 0;
339 blkfree((Char **) t);
340 /* The sky is falling, the sky is falling! */
341
342 case ENOMEM:
343 stderror(ERR_SYSTEM, f, strerror(errno));
344
345 case ENOENT:
346 break;
347
348 default:
349 if (exerr == 0) {
350 exerr = strerror(errno);
351 if (expath)
352 xfree((ptr_t) expath);
353 expath = Strsave(sf);
354 Vexpath = expath;
355 }
356 }
357 }
358
359 /*ARGSUSED*/
360 void
361 execash(t, kp)
362 Char **t;
363 register struct command *kp;
364 {
365 int saveIN, saveOUT, saveDIAG, saveSTD;
366 int oSHIN;
367 int oSHOUT;
368 int oSHERR;
369 int oOLDSTD;
370 jmp_buf osetexit;
371 int my_reenter;
372 int odidfds;
373 sig_t osigint, osigquit, osigterm;
374
375 if (chkstop == 0 && setintr)
376 panystop(0);
377 /*
378 * Hmm, we don't really want to do that now because we might
379 * fail, but what is the choice
380 */
381 rechist();
382
383 osigint = signal(SIGINT, parintr);
384 osigquit = signal(SIGQUIT, parintr);
385 osigterm = signal(SIGTERM, parterm);
386
387 odidfds = didfds;
388 oSHIN = SHIN;
389 oSHOUT = SHOUT;
390 oSHERR = SHERR;
391 oOLDSTD = OLDSTD;
392
393 saveIN = dcopy(SHIN, -1);
394 saveOUT = dcopy(SHOUT, -1);
395 saveDIAG = dcopy(SHERR, -1);
396 saveSTD = dcopy(OLDSTD, -1);
397
398 lshift(kp->t_dcom, 1);
399
400 getexit(osetexit);
401
402 if ((my_reenter = setexit()) == 0) {
403 SHIN = dcopy(0, -1);
404 SHOUT = dcopy(1, -1);
405 SHERR = dcopy(2, -1);
406 didfds = 0;
407 doexec(t, kp);
408 }
409
410 (void) signal(SIGINT, osigint);
411 (void) signal(SIGQUIT, osigquit);
412 (void) signal(SIGTERM, osigterm);
413
414 doneinp = 0;
415 didfds = odidfds;
416 (void) close(SHIN);
417 (void) close(SHOUT);
418 (void) close(SHERR);
419 (void) close(OLDSTD);
420 SHIN = dmove(saveIN, oSHIN);
421 SHOUT = dmove(saveOUT, oSHOUT);
422 SHERR = dmove(saveDIAG, oSHERR);
423 OLDSTD = dmove(saveSTD, oOLDSTD);
424
425 resexit(osetexit);
426 if (my_reenter)
427 stderror(ERR_SILENT);
428 }
429
430 void
431 xechoit(t)
432 Char **t;
433 {
434 if (adrof(STRecho)) {
435 (void) fflush(csherr);
436 blkpr(csherr, t);
437 (void) fputc('\n', csherr);
438 }
439 }
440
441 void
442 /*ARGSUSED*/
443 dohash(v, t)
444 Char **v;
445 struct command *t;
446 {
447 DIR *dirp;
448 register struct dirent *dp;
449 register int cnt;
450 int i = 0;
451 struct varent *pathv = adrof(STRpath);
452 Char **pv;
453 int hashval;
454
455 havhash = 1;
456 for (cnt = 0; cnt < sizeof xhash; cnt++)
457 xhash[cnt] = 0;
458 if (pathv == 0)
459 return;
460 for (pv = pathv->vec; *pv; pv++, i++) {
461 if (pv[0][0] != '/')
462 continue;
463 dirp = opendir(short2str(*pv));
464 if (dirp == NULL)
465 continue;
466 while ((dp = readdir(dirp)) != NULL) {
467 if (dp->d_ino == 0)
468 continue;
469 if (dp->d_name[0] == '.' &&
470 (dp->d_name[1] == '\0' ||
471 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
472 continue;
473 hashval = hash(hashname(str2short(dp->d_name)), i);
474 bis(xhash, hashval);
475 /* tw_add_comm_name (dp->d_name); */
476 }
477 (void) closedir(dirp);
478 }
479 }
480
481 void
482 /*ARGSUSED*/
483 dounhash(v, t)
484 Char **v;
485 struct command *t;
486 {
487 havhash = 0;
488 }
489
490 void
491 /*ARGSUSED*/
492 hashstat(v, t)
493 Char **v;
494 struct command *t;
495 {
496 if (hits + misses)
497 (void) fprintf(cshout, "%d hits, %d misses, %d%%\n",
498 hits, misses, 100 * hits / (hits + misses));
499 }
500
501 /*
502 * Hash a command name.
503 */
504 static int
505 hashname(cp)
506 register Char *cp;
507 {
508 register long h = 0;
509
510 while (*cp)
511 h = hash(h, *cp++);
512 return ((int) h);
513 }
514
515 static int
516 iscommand(name)
517 Char *name;
518 {
519 register Char **pv;
520 register Char *sav;
521 register struct varent *v;
522 register bool slash = any(short2str(name), '/');
523 register int hashval = 0, hashval1, i;
524
525 v = adrof(STRpath);
526 if (v == 0 || v->vec[0] == 0 || slash)
527 pv = justabs;
528 else
529 pv = v->vec;
530 sav = Strspl(STRslash, name); /* / command name for postpending */
531 if (havhash)
532 hashval = hashname(name);
533 i = 0;
534 do {
535 if (!slash && pv[0][0] == '/' && havhash) {
536 hashval1 = hash(hashval, i);
537 if (!bit(xhash, hashval1))
538 goto cont;
539 }
540 if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */
541 if (executable(NULL, name, 0)) {
542 xfree((ptr_t) sav);
543 return i + 1;
544 }
545 }
546 else {
547 if (executable(*pv, sav, 0)) {
548 xfree((ptr_t) sav);
549 return i + 1;
550 }
551 }
552 cont:
553 pv++;
554 i++;
555 } while (*pv);
556 xfree((ptr_t) sav);
557 return 0;
558 }
559
560 /* Also by:
561 * Andreas Luik <luik (at) isaak.isa.de>
562 * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
563 * Azenberstr. 35
564 * D-7000 Stuttgart 1
565 * West-Germany
566 * is the executable() routine below and changes to iscommand().
567 * Thanks again!!
568 */
569
570 /*
571 * executable() examines the pathname obtained by concatenating dir and name
572 * (dir may be NULL), and returns 1 either if it is executable by us, or
573 * if dir_ok is set and the pathname refers to a directory.
574 * This is a bit kludgy, but in the name of optimization...
575 */
576 static int
577 executable(dir, name, dir_ok)
578 Char *dir, *name;
579 bool dir_ok;
580 {
581 struct stat stbuf;
582 Char path[MAXPATHLEN + 1], *dp, *sp;
583 char *strname;
584
585 if (dir && *dir) {
586 for (dp = path, sp = dir; *sp; *dp++ = *sp++)
587 if (dp == &path[MAXPATHLEN + 1]) {
588 *--dp = '\0';
589 break;
590 }
591 for (sp = name; *sp; *dp++ = *sp++)
592 if (dp == &path[MAXPATHLEN + 1]) {
593 *--dp = '\0';
594 break;
595 }
596 *dp = '\0';
597 strname = short2str(path);
598 }
599 else
600 strname = short2str(name);
601 return (stat(strname, &stbuf) != -1 &&
602 ((S_ISREG(stbuf.st_mode) &&
603 /* save time by not calling access() in the hopeless case */
604 (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
605 access(strname, X_OK) == 0) ||
606 (dir_ok && S_ISDIR(stbuf.st_mode))));
607 }
608
609 /* The dowhich() is by:
610 * Andreas Luik <luik (at) isaak.isa.de>
611 * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
612 * Azenberstr. 35
613 * D-7000 Stuttgart 1
614 * West-Germany
615 * Thanks!!
616 */
617 /*ARGSUSED*/
618 void
619 dowhich(v, c)
620 register Char **v;
621 struct command *c;
622 {
623 struct wordent lex[3];
624 struct varent *vp;
625
626 lex[0].next = &lex[1];
627 lex[1].next = &lex[2];
628 lex[2].next = &lex[0];
629
630 lex[0].prev = &lex[2];
631 lex[1].prev = &lex[0];
632 lex[2].prev = &lex[1];
633
634 lex[0].word = STRNULL;
635 lex[2].word = STRret;
636
637 while (*++v) {
638 if ((vp = adrof1(*v, &aliases)) != NULL) {
639 (void) fprintf(cshout, "%s: \t aliased to ", vis_str(*v));
640 blkpr(cshout, vp->vec);
641 (void) fputc('\n', cshout);
642 }
643 else {
644 lex[1].word = *v;
645 tellmewhat(lex);
646 }
647 }
648 }
649
650 static void
651 tellmewhat(lex)
652 struct wordent *lex;
653 {
654 register int i;
655 register struct biltins *bptr;
656 register struct wordent *sp = lex->next;
657 bool aliased = 0;
658 Char *s0, *s1, *s2;
659 Char qc;
660
661 if (adrof1(sp->word, &aliases)) {
662 alias(lex);
663 sp = lex->next;
664 aliased = 1;
665 }
666
667 s0 = sp->word; /* to get the memory freeing right... */
668
669 /* handle quoted alias hack */
670 if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
671 (sp->word)++;
672
673 /* do quoting, if it hasn't been done */
674 s1 = s2 = sp->word;
675 while (*s2)
676 switch (*s2) {
677 case '\'':
678 case '"':
679 qc = *s2++;
680 while (*s2 && *s2 != qc)
681 *s1++ = *s2++ | QUOTE;
682 if (*s2)
683 s2++;
684 break;
685 case '\\':
686 if (*++s2)
687 *s1++ = *s2++ | QUOTE;
688 break;
689 default:
690 *s1++ = *s2++;
691 }
692 *s1 = '\0';
693
694 for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
695 if (eq(sp->word, str2short(bptr->bname))) {
696 if (aliased)
697 prlex(cshout, lex);
698 (void) fprintf(cshout, "%s: shell built-in command.\n",
699 vis_str(sp->word));
700 sp->word = s0; /* we save and then restore this */
701 return;
702 }
703 }
704
705 if ((i = iscommand(strip(sp->word))) != 0) {
706 register Char **pv;
707 register struct varent *v;
708 bool slash = any(short2str(sp->word), '/');
709
710 v = adrof(STRpath);
711 if (v == 0 || v->vec[0] == 0 || slash)
712 pv = justabs;
713 else
714 pv = v->vec;
715
716 while (--i)
717 pv++;
718 if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
719 sp->word = Strspl(STRdotsl, sp->word);
720 prlex(cshout, lex);
721 xfree((ptr_t) sp->word);
722 sp->word = s0; /* we save and then restore this */
723 return;
724 }
725 s1 = Strspl(*pv, STRslash);
726 sp->word = Strspl(s1, sp->word);
727 xfree((ptr_t) s1);
728 prlex(cshout, lex);
729 xfree((ptr_t) sp->word);
730 }
731 else {
732 if (aliased)
733 prlex(cshout, lex);
734 (void) fprintf(csherr, "%s: Command not found.\n", vis_str(sp->word));
735 }
736 sp->word = s0; /* we save and then restore this */
737 }
738