Take -lgnuregex back out. Linking with it causes 'make install' to fail.
[unix-history] / bin / csh / exec.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1980, 1991 The Regents of the University of California.
3 * 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
35static char sccsid[] = "@(#)exec.c 5.17 (Berkeley) 6/17/91";
36#endif /* not lint */
37
38#include <sys/types.h>
39#include <dirent.h>
40#include <fcntl.h>
41#include <errno.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45#if __STDC__
46# include <stdarg.h>
47#else
48# include <varargs.h>
49#endif
50
51#include "csh.h"
52#include "extern.h"
53
54/*
55 * System level search and execute of a command. We look in each directory
56 * for the specified command name. If the name contains a '/' then we
57 * execute only the full path name. If there is no search path then we
58 * execute only full path names.
59 */
60extern char **environ;
61
62/*
63 * As we search for the command we note the first non-trivial error
64 * message for presentation to the user. This allows us often
65 * to show that a file has the wrong mode/no access when the file
66 * is not in the last component of the search path, so we must
67 * go on after first detecting the error.
68 */
69static char *exerr; /* Execution error message */
70static Char *expath; /* Path for exerr */
71
72/*
73 * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
74 * to hash execs. If it is allocated (havhash true), then to tell
75 * whether ``name'' is (possibly) present in the i'th component
76 * of the variable path, you look at the bit in xhash indexed by
77 * hash(hashname("name"), i). This is setup automatically
78 * after .login is executed, and recomputed whenever ``path'' is
79 * changed.
80 * The two part hash function is designed to let texec() call the
81 * more expensive hashname() only once and the simple hash() several
82 * times (once for each path component checked).
83 * Byte size is assumed to be 8.
84 */
85#define HSHSIZ 8192 /* 1k bytes */
86#define HSHMASK (HSHSIZ - 1)
87#define HSHMUL 243
88static char xhash[HSHSIZ / 8];
89
90#define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK)
91#define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
92#define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */
93static int hits, misses;
94
95/* Dummy search path for just absolute search when no path */
96static Char *justabs[] = {STRNULL, 0};
97
98static void pexerr __P((void));
99static void texec __P((Char *, Char **));
100static int hashname __P((Char *));
101
102void
103doexec(t)
104 register struct command *t;
105{
106 register Char *dp, **pv, **av, *sav;
107 register struct varent *v;
108 register bool slash;
109 register int hashval = 0, hashval1, i;
110 Char *blk[2];
111
112 /*
113 * Glob the command name. We will search $path even if this does something,
114 * as in sh but not in csh. One special case: if there is no PATH, then we
115 * execute only commands which start with '/'.
116 */
117 blk[0] = t->t_dcom[0];
118 blk[1] = 0;
119 gflag = 0, tglob(blk);
120 if (gflag) {
121 pv = globall(blk);
122 if (pv == 0) {
123 setname(short2str(blk[0]));
124 stderror(ERR_NAME | ERR_NOMATCH);
125 }
126 gargv = 0;
127 }
128 else
129 pv = saveblk(blk);
130
131 trim(pv);
132
133 exerr = 0;
134 expath = Strsave(pv[0]);
135 Vexpath = expath;
136
137 v = adrof(STRpath);
138 if (v == 0 && expath[0] != '/') {
139 blkfree(pv);
140 pexerr();
141 }
142 slash = any(short2str(expath), '/');
143
144 /*
145 * Glob the argument list, if necessary. Otherwise trim off the quote bits.
146 */
147 gflag = 0;
148 av = &t->t_dcom[1];
149 tglob(av);
150 if (gflag) {
151 av = globall(av);
152 if (av == 0) {
153 blkfree(pv);
154 setname(short2str(expath));
155 stderror(ERR_NAME | ERR_NOMATCH);
156 }
157 gargv = 0;
158 }
159 else
160 av = saveblk(av);
161
162 blkfree(t->t_dcom);
163 t->t_dcom = blkspl(pv, av);
164 xfree((ptr_t) pv);
165 xfree((ptr_t) av);
166 av = t->t_dcom;
167 trim(av);
168
169 if (*av == NULL || **av == '\0')
170 pexerr();
171
172 xechoit(av); /* Echo command if -x */
173 /*
174 * Since all internal file descriptors are set to close on exec, we don't
175 * need to close them explicitly here. Just reorient ourselves for error
176 * messages.
177 */
178 SHIN = 0;
179 SHOUT = 1;
180 SHDIAG = 2;
181 OLDSTD = 0;
182 /*
183 * We must do this AFTER any possible forking (like `foo` in glob) so that
184 * this shell can still do subprocesses.
185 */
186 (void) sigsetmask((sigset_t) 0);
187 /*
188 * If no path, no words in path, or a / in the filename then restrict the
189 * command search.
190 */
191 if (v == 0 || v->vec[0] == 0 || slash)
192 pv = justabs;
193 else
194 pv = v->vec;
195 sav = Strspl(STRslash, *av);/* / command name for postpending */
196 Vsav = sav;
197 if (havhash)
198 hashval = hashname(*av);
199 i = 0;
200 hits++;
201 do {
202 /*
203 * Try to save time by looking at the hash table for where this command
204 * could be. If we are doing delayed hashing, then we put the names in
205 * one at a time, as the user enters them. This is kinda like Korn
206 * Shell's "tracked aliases".
207 */
208 if (!slash && pv[0][0] == '/' && havhash) {
209 hashval1 = hash(hashval, i);
210 if (!bit(xhash, hashval1))
211 goto cont;
212 }
213 if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */
214 texec(*av, av);
215 else {
216 dp = Strspl(*pv, sav);
217 Vdp = dp;
218 texec(dp, av);
219 Vdp = 0;
220 xfree((ptr_t) dp);
221 }
222 misses++;
223cont:
224 pv++;
225 i++;
226 } while (*pv);
227 hits--;
228 Vsav = 0;
229 xfree((ptr_t) sav);
230 pexerr();
231}
232
233static void
234pexerr()
235{
236 /* Couldn't find the damn thing */
237 if (expath) {
238 setname(short2str(expath));
239 Vexpath = 0;
240 xfree((ptr_t) expath);
241 expath = 0;
242 }
243 else
244 setname("");
245 if (exerr)
246 stderror(ERR_NAME | ERR_STRING, exerr);
247 stderror(ERR_NAME | ERR_COMMAND);
248}
249
250/*
251 * Execute command f, arg list t.
252 * Record error message if not found.
253 * Also do shell scripts here.
254 */
255static void
256texec(sf, st)
257 Char *sf;
258 register Char **st;
259{
260 register char **t;
261 register char *f;
262 register struct varent *v;
263 register Char **vp;
264 Char *lastsh[2];
265 int fd;
266 unsigned char c;
267 Char *st0, **ost;
268
269 /* The order for the conversions is significant */
270 t = short2blk(st);
271 f = short2str(sf);
272 Vt = t;
273 errno = 0; /* don't use a previous error */
274 (void) execve(f, t, environ);
275 Vt = 0;
276 blkfree((Char **) t);
277 switch (errno) {
278
279 case ENOEXEC:
280 /*
281 * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute
282 * it, don't feed it to the shell if it looks like a binary!
283 */
284 if ((fd = open(f, O_RDONLY)) != -1) {
285 if (read(fd, (char *) &c, 1) == 1) {
286 if (!Isprint(c) && (c != '\n' && c != '\t')) {
287 (void) close(fd);
288 /*
289 * We *know* what ENOEXEC means.
290 */
291 stderror(ERR_ARCH, f, strerror(errno));
292 }
293 }
294#ifdef _PATH_BSHELL
295 else
296 c = '#';
297#endif
298 (void) close(fd);
299 }
300 /*
301 * If there is an alias for shell, then put the words of the alias in
302 * front of the argument list replacing the command name. Note no
303 * interpretation of the words at this point.
304 */
305 v = adrof1(STRshell, &aliases);
306 if (v == 0) {
307 vp = lastsh;
308 vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH;
309 vp[1] = NULL;
310#ifdef _PATH_BSHELL
311 if (fd != -1 && c != '#')
312 vp[0] = STR_BSHELL;
313#endif
314 }
315 else
316 vp = v->vec;
317 st0 = st[0];
318 st[0] = sf;
319 ost = st;
320 st = blkspl(vp, st); /* Splice up the new arglst */
321 ost[0] = st0;
322 sf = *st;
323 /* The order for the conversions is significant */
324 t = short2blk(st);
325 f = short2str(sf);
326 xfree((ptr_t) st);
327 Vt = t;
328 (void) execve(f, t, environ);
329 Vt = 0;
330 blkfree((Char **) t);
331 /* The sky is falling, the sky is falling! */
332
333 case ENOMEM:
334 stderror(ERR_SYSTEM, f, strerror(errno));
335
336 case ENOENT:
337 break;
338
339 default:
340 if (exerr == 0) {
341 exerr = strerror(errno);
342 if (expath)
343 xfree((ptr_t) expath);
344 expath = Strsave(sf);
345 Vexpath = expath;
346 }
347 }
348}
349
350/*ARGSUSED*/
351void
352execash(t, kp)
353 char **t;
354 register struct command *kp;
355{
356 if (chkstop == 0 && setintr)
357 panystop(0);
358 rechist();
359 (void) signal(SIGINT, parintr);
360 (void) signal(SIGQUIT, parintr);
361 (void) signal(SIGTERM, parterm); /* if doexec loses, screw */
362 lshift(kp->t_dcom, 1);
363 exiterr = 1;
364 doexec(kp);
365 /* NOTREACHED */
366}
367
368void
369xechoit(t)
370 Char **t;
371{
372 if (adrof(STRecho)) {
373 flush();
374 haderr = 1;
375 blkpr(t), xputchar('\n');
376 haderr = 0;
377 }
378}
379
380/*VARARGS0*/
381void
382dohash()
383{
384 DIR *dirp;
385 register struct dirent *dp;
386 register int cnt;
387 int i = 0;
388 struct varent *v = adrof(STRpath);
389 Char **pv;
390 int hashval;
391
392 havhash = 1;
393 for (cnt = 0; cnt < sizeof xhash; cnt++)
394 xhash[cnt] = 0;
395 if (v == 0)
396 return;
397 for (pv = v->vec; *pv; pv++, i++) {
398 if (pv[0][0] != '/')
399 continue;
400 dirp = opendir(short2str(*pv));
401 if (dirp == NULL)
402 continue;
403 while ((dp = readdir(dirp)) != NULL) {
404 if (dp->d_ino == 0)
405 continue;
406 if (dp->d_name[0] == '.' &&
407 (dp->d_name[1] == '\0' ||
408 dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
409 continue;
410 hashval = hash(hashname(str2short(dp->d_name)), i);
411 bis(xhash, hashval);
412 /* tw_add_comm_name (dp->d_name); */
413 }
414 (void) closedir(dirp);
415 }
416}
417
418void
419dounhash()
420{
421 havhash = 0;
422}
423
424void
425hashstat()
426{
427 if (hits + misses)
428 xprintf("%d hits, %d misses, %d%%\n",
429 hits, misses, 100 * hits / (hits + misses));
430}
431
432/*
433 * Hash a command name.
434 */
435static int
436hashname(cp)
437 register Char *cp;
438{
439 register long h = 0;
440
441 while (*cp)
442 h = hash(h, *cp++);
443 return ((int) h);
444}