Bug Summary

File:src/bin/csh/exec.c
Warning:line 132, column 22
Array access (from variable 'pv') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

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