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