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