File: | src/bin/csh/exec.c |
Warning: | line 132, column 22 Array access (from variable 'pv') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | */ | |||
53 | extern 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 | */ | |||
62 | static char *exerr; /* Execution error message */ | |||
63 | static 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 | |||
81 | static 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 */ | |||
86 | static int hits, misses; | |||
87 | ||||
88 | /* Dummy search path for just absolute search when no path */ | |||
89 | static Char *justabs[] = {STRNULL, 0}; | |||
90 | ||||
91 | static void pexerr(void); | |||
92 | static void texec(Char *, Char **); | |||
93 | static int hashname(Char *); | |||
94 | static int tellmewhat(struct wordent *, Char *, int len); | |||
95 | static int executable(Char *, Char *, bool); | |||
96 | static int iscommand(Char *); | |||
97 | ||||
98 | ||||
99 | void | |||
100 | /*ARGSUSED*/ | |||
101 | doexec(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) { | |||
119 | pv = globall(blk); | |||
120 | if (pv == 0) { | |||
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]); | |||
| ||||
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++; | |||
222 | cont: | |||
223 | pv++; | |||
224 | i++; | |||
225 | } while (*pv); | |||
226 | hits--; | |||
227 | Vsav = 0; | |||
228 | free(sav); | |||
229 | pexerr(); | |||
230 | } | |||
231 | ||||
232 | static void | |||
233 | pexerr(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 | */ | |||
254 | static void | |||
255 | texec(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*/ | |||
344 | void | |||
345 | execash(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) | |||
| ||||
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) { | |||
385 | SHIN = dcopy(0, -1); | |||
386 | SHOUT = dcopy(1, -1); | |||
387 | SHERR = dcopy(2, -1); | |||
388 | didfds = 0; | |||
389 | doexec(t, kp); | |||
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 | ||||
412 | void | |||
413 | xechoit(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 | ||||
422 | void | |||
423 | /*ARGSUSED*/ | |||
424 | dohash(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 | ||||
460 | void | |||
461 | /*ARGSUSED*/ | |||
462 | dounhash(Char **v, struct command *t) | |||
463 | { | |||
464 | havhash = 0; | |||
465 | } | |||
466 | ||||
467 | void | |||
468 | /*ARGSUSED*/ | |||
469 | hashstat(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 | */ | |||
479 | static int | |||
480 | hashname(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 | ||||
489 | static int | |||
490 | iscommand(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 | } | |||
525 | cont: | |||
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 | */ | |||
549 | static int | |||
550 | executable(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*/ | |||
589 | void | |||
590 | dowhich(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 | ||||
620 | static int | |||
621 | tellmewhat(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 | } |