|
1 // exec.c - command execution |
|
2 // |
|
3 // © Portions Copyright (c) Symbian Software Ltd 2007 - 2008. All rights reserved. |
|
4 // |
|
5 /* |
|
6 * This file is part of zsh, the Z shell. |
|
7 * |
|
8 * Copyright (c) 1992-1997 Paul Falstad |
|
9 * All rights reserved. |
|
10 * |
|
11 * Permission is hereby granted, without written agreement and without |
|
12 * license or royalty fees, to use, copy, modify, and distribute this |
|
13 * software and to distribute modified versions of this software for any |
|
14 * purpose, provided that the above copyright notice and the following |
|
15 * two paragraphs appear in all copies of this software. |
|
16 * |
|
17 * In no event shall Paul Falstad or the Zsh Development Group be liable |
|
18 * to any party for direct, indirect, special, incidental, or consequential |
|
19 * damages arising out of the use of this software and its documentation, |
|
20 * even if Paul Falstad and the Zsh Development Group have been advised of |
|
21 * the possibility of such damage. |
|
22 * |
|
23 * Paul Falstad and the Zsh Development Group specifically disclaim any |
|
24 * warranties, including, but not limited to, the implied warranties of |
|
25 * merchantability and fitness for a particular purpose. The software |
|
26 * provided hereunder is on an "as is" basis, and Paul Falstad and the |
|
27 * Zsh Development Group have no obligation to provide maintenance, |
|
28 * support, updates, enhancements, or modifications. |
|
29 * |
|
30 */ |
|
31 |
|
32 #include "zsh.mdh" |
|
33 #include "exec.pro" |
|
34 |
|
35 #ifdef __SYMBIAN32__ |
|
36 #ifdef __WINSCW__ |
|
37 #pragma warn_unusedarg off |
|
38 #pragma warn_possunwant off |
|
39 #endif//__WINSCW__ |
|
40 #endif//__SYMBIAN32__ |
|
41 |
|
42 #ifdef __SYMBIAN32__ |
|
43 #include <pthread.h> |
|
44 #include <sys/param.h> |
|
45 #include <sys/select.h> |
|
46 #include <sys/stat.h> |
|
47 #include <stdlib.h> |
|
48 #include "dummy.h" |
|
49 #endif //__SYMBIAN32__ |
|
50 |
|
51 #ifdef __SYMBIAN32__ |
|
52 typedef struct |
|
53 { |
|
54 Eprog p; |
|
55 int dont_change_job; |
|
56 int exiting; |
|
57 } st_exec; |
|
58 #endif // __SYMBIAN32__ |
|
59 |
|
60 /* used to suppress ERREXIT and trapping of SIGZERR, SIGEXIT. */ |
|
61 |
|
62 /**/ |
|
63 int noerrexit; |
|
64 |
|
65 /* suppress error messages */ |
|
66 |
|
67 /**/ |
|
68 mod_export int noerrs; |
|
69 |
|
70 /* do not save history on exec and exit */ |
|
71 |
|
72 /**/ |
|
73 int nohistsave; |
|
74 |
|
75 /* error/break flag */ |
|
76 |
|
77 /**/ |
|
78 mod_export int errflag; |
|
79 |
|
80 /* Status of return from a trap */ |
|
81 |
|
82 /**/ |
|
83 int trapreturn; |
|
84 |
|
85 /* != 0 if this is a subshell */ |
|
86 |
|
87 /**/ |
|
88 int subsh; |
|
89 |
|
90 /* != 0 if we have a return pending */ |
|
91 |
|
92 /**/ |
|
93 mod_export int retflag; |
|
94 |
|
95 /**/ |
|
96 long lastval2; |
|
97 |
|
98 /* The table of file descriptors. A table element is zero if the * |
|
99 * corresponding fd is not used by the shell. It is greater than * |
|
100 * 1 if the fd is used by a <(...) or >(...) substitution and 1 if * |
|
101 * it is an internal file descriptor which must be closed before * |
|
102 * executing an external command. The first ten elements of the * |
|
103 * table is not used. A table element is set by movefd and cleard * |
|
104 * by zclose. */ |
|
105 |
|
106 /**/ |
|
107 char *fdtable; |
|
108 |
|
109 /* The allocated size of fdtable */ |
|
110 |
|
111 /**/ |
|
112 int fdtable_size; |
|
113 |
|
114 /* The highest fd that marked with nonzero in fdtable */ |
|
115 |
|
116 /**/ |
|
117 int max_zsh_fd; |
|
118 |
|
119 /* input fd from the coprocess */ |
|
120 |
|
121 /**/ |
|
122 mod_export int coprocin; |
|
123 |
|
124 /* output fd from the coprocess */ |
|
125 |
|
126 /**/ |
|
127 mod_export int coprocout; |
|
128 |
|
129 /* != 0 if the line editor is active */ |
|
130 |
|
131 /**/ |
|
132 mod_export int zleactive; |
|
133 |
|
134 /* pid of process undergoing 'process substitution' */ |
|
135 |
|
136 /**/ |
|
137 pid_t cmdoutpid; |
|
138 |
|
139 /* exit status of process undergoing 'process substitution' */ |
|
140 |
|
141 /**/ |
|
142 int cmdoutval; |
|
143 |
|
144 /* The context in which a shell function is called, see SFC_* in zsh.h. */ |
|
145 |
|
146 /**/ |
|
147 mod_export int sfcontext; |
|
148 |
|
149 /* Stack to save some variables before executing a signal handler function */ |
|
150 |
|
151 /**/ |
|
152 struct execstack *exstack; |
|
153 |
|
154 /* Stack with names of functions currently active. */ |
|
155 |
|
156 /**/ |
|
157 mod_export Funcstack funcstack; |
|
158 |
|
159 #define execerr() if (!forked) { lastval = 1; goto done; } else _exit(1) |
|
160 |
|
161 static LinkList args; |
|
162 static int doneps4; |
|
163 static char *STTYval; |
|
164 |
|
165 /* Execution functions. */ |
|
166 |
|
167 static int (*execfuncs[WC_COUNT-WC_CURSH]) _((Estate, int)) = { |
|
168 execcursh, exectime, execfuncdef, execfor, execselect, |
|
169 execwhile, execrepeat, execcase, execif, execcond, |
|
170 execarith, execautofn, exectry |
|
171 }; |
|
172 |
|
173 /* structure for command builtin for when it is used with -v or -V */ |
|
174 static struct builtin commandbn = |
|
175 BUILTIN(0, 0, bin_whence, 0, -1, BIN_COMMAND, "vV", NULL); |
|
176 |
|
177 |
|
178 /* parse string into a list */ |
|
179 |
|
180 /**/ |
|
181 mod_export Eprog |
|
182 parse_string(char *s) |
|
183 { |
|
184 Eprog p; |
|
185 int oldlineno = lineno; |
|
186 |
|
187 lexsave(); |
|
188 inpush(s, INP_LINENO, NULL); |
|
189 strinbeg(0); |
|
190 lineno = 1; |
|
191 p = parse_list(); |
|
192 lineno = oldlineno; |
|
193 if (tok == LEXERR && !lastval) |
|
194 lastval = 1; |
|
195 strinend(); |
|
196 inpop(); |
|
197 lexrestore(); |
|
198 return p; |
|
199 } |
|
200 |
|
201 /**/ |
|
202 #ifdef HAVE_GETRLIMIT |
|
203 |
|
204 /* the resource limits for the shell and its children */ |
|
205 |
|
206 /**/ |
|
207 mod_export struct rlimit current_limits[RLIM_NLIMITS], limits[RLIM_NLIMITS]; |
|
208 |
|
209 /**/ |
|
210 mod_export int |
|
211 zsetlimit(int limnum, char *nam) |
|
212 { |
|
213 if (limits[limnum].rlim_max != current_limits[limnum].rlim_max || |
|
214 limits[limnum].rlim_cur != current_limits[limnum].rlim_cur) { |
|
215 if (setrlimit(limnum, limits + limnum)) { |
|
216 if (nam) |
|
217 zwarnnam(nam, "setrlimit failed: %e", NULL, errno); |
|
218 return -1; |
|
219 } |
|
220 current_limits[limnum] = limits[limnum]; |
|
221 } |
|
222 return 0; |
|
223 } |
|
224 |
|
225 /**/ |
|
226 mod_export int |
|
227 setlimits(char *nam) |
|
228 { |
|
229 int limnum; |
|
230 int ret = 0; |
|
231 |
|
232 for (limnum = 0; limnum < RLIM_NLIMITS; limnum++) |
|
233 if (zsetlimit(limnum, nam)) |
|
234 ret++; |
|
235 return ret; |
|
236 } |
|
237 |
|
238 /**/ |
|
239 #endif /* HAVE_GETRLIMIT */ |
|
240 |
|
241 /* fork and set limits */ |
|
242 |
|
243 /**/ |
|
244 #ifndef __SYMBIAN32__ |
|
245 static pid_t |
|
246 zfork(struct timeval *tv) |
|
247 { |
|
248 pid_t pid; |
|
249 struct timezone dummy_tz; |
|
250 |
|
251 /* |
|
252 * Is anybody willing to explain this test? |
|
253 */ |
|
254 if (thisjob != -1 && thisjob >= jobtabsize - 1 && !expandjobtab()) { |
|
255 zerr("job table full", NULL, 0); |
|
256 return -1; |
|
257 } |
|
258 if (tv) |
|
259 gettimeofday(tv, &dummy_tz); |
|
260 pid = fork(); |
|
261 if (pid == -1) { |
|
262 zerr("fork failed: %e", NULL, errno); |
|
263 return -1; |
|
264 } |
|
265 #ifdef HAVE_GETRLIMIT |
|
266 if (!pid) |
|
267 /* set resource limits for the child process */ |
|
268 setlimits(NULL); |
|
269 #endif |
|
270 return pid; |
|
271 } |
|
272 #endif //__SYMBIAN32__ |
|
273 |
|
274 /* |
|
275 * Allen Edeln gebiet ich Andacht, |
|
276 * Hohen und Niedern von Heimdalls Geschlecht; |
|
277 * Ich will list_pipe's Wirken kuenden |
|
278 * Die aeltesten Sagen, der ich mich entsinne... |
|
279 * |
|
280 * In most shells, if you do something like: |
|
281 * |
|
282 * cat foo | while read a; do grep $a bar; done |
|
283 * |
|
284 * the shell forks and executes the loop in the sub-shell thus created. |
|
285 * In zsh this traditionally executes the loop in the current shell, which |
|
286 * is nice to have if the loop does something to change the shell, like |
|
287 * setting parameters or calling builtins. |
|
288 * Putting the loop in a sub-shell makes life easy, because the shell only |
|
289 * has to put it into the job-structure and then treats it as a normal |
|
290 * process. Suspending and interrupting is no problem then. |
|
291 * Some years ago, zsh either couldn't suspend such things at all, or |
|
292 * it got really messed up when users tried to do it. As a solution, we |
|
293 * implemented the list_pipe-stuff, which has since then become a reason |
|
294 * for many nightmares. |
|
295 * Pipelines like the one above are executed by the functions in this file |
|
296 * which call each other (and sometimes recursively). The one above, for |
|
297 * example would lead to a function call stack roughly like: |
|
298 * |
|
299 * execlist->execpline->execcmd->execwhile->execlist->execpline |
|
300 * |
|
301 * (when waiting for the grep, ignoring execpline2 for now). At this time, |
|
302 * zsh has built two job-table entries for it: one for the cat and one for |
|
303 * the grep. If the user hits ^Z at this point (and jobbing is used), the |
|
304 * shell is notified that the grep was suspended. The list_pipe flag is |
|
305 * used to tell the execpline where it was waiting that it was in a pipeline |
|
306 * with a shell construct at the end (which may also be a shell function or |
|
307 * several other things). When zsh sees the suspended grep, it forks to let |
|
308 * the sub-shell execute the rest of the while loop. The parent shell walks |
|
309 * up in the function call stack to the first execpline. There it has to find |
|
310 * out that it has just forked and then has to add information about the sub- |
|
311 * shell (its pid and the text for it) in the job entry of the cat. The pid |
|
312 * is passed down in the list_pipe_pid variable. |
|
313 * But there is a problem: the suspended grep is a child of the parent shell |
|
314 * and can't be adopted by the sub-shell. So the parent shell also has to |
|
315 * keep the information about this process (more precisely: this pipeline) |
|
316 * by keeping the job table entry it created for it. The fact that there |
|
317 * are two jobs which have to be treated together is remembered by setting |
|
318 * the STAT_SUPERJOB flag in the entry for the cat-job (which now also |
|
319 * contains a process-entry for the whole loop -- the sub-shell) and by |
|
320 * setting STAT_SUBJOB in the job of the grep-job. With that we can keep |
|
321 * sub-jobs from being displayed and we can handle an fg/bg on the super- |
|
322 * job correctly. When the super-job is continued, the shell also wakes up |
|
323 * the sub-job. But then, the grep will exit sometime. Now the parent shell |
|
324 * has to remember not to try to wake it up again (in case of another ^Z). |
|
325 * It also has to wake up the sub-shell (which suspended itself immediately |
|
326 * after creation), so that the rest of the loop is executed by it. |
|
327 * But there is more: when the sub-shell is created, the cat may already |
|
328 * have exited, so we can't put the sub-shell in the process group of it. |
|
329 * In this case, we put the sub-shell in the process group of the parent |
|
330 * shell and in any case, the sub-shell has to put all commands executed |
|
331 * by it into its own process group, because only this way the parent |
|
332 * shell can control them since it only knows the process group of the sub- |
|
333 * shell. Of course, this information is also important when putting a job |
|
334 * in the foreground, where we have to attach its process group to the |
|
335 * controlling tty. |
|
336 * All this is made more difficult because we have to handle return values |
|
337 * correctly. If the grep is signaled, its exit status has to be propagated |
|
338 * back to the parent shell which needs it to set the exit status of the |
|
339 * super-job. And of course, when the grep is signaled (including ^C), the |
|
340 * loop has to be stopped, etc. |
|
341 * The code for all this is distributed over three files (exec.c, jobs.c, |
|
342 * and signals.c) and none of them is a simple one. So, all in all, there |
|
343 * may still be bugs, but considering the complexity (with race conditions, |
|
344 * signal handling, and all that), this should probably be expected. |
|
345 */ |
|
346 |
|
347 /**/ |
|
348 int list_pipe = 0, simple_pline = 0; |
|
349 |
|
350 static pid_t list_pipe_pid; |
|
351 static struct timeval list_pipe_start; |
|
352 static int nowait, pline_level = 0; |
|
353 static int list_pipe_child = 0, list_pipe_job; |
|
354 static char list_pipe_text[JOBTEXTSIZE]; |
|
355 |
|
356 /* execute a current shell command */ |
|
357 |
|
358 /**/ |
|
359 static int |
|
360 execcursh(Estate state, int do_exec) |
|
361 { |
|
362 Wordcode end = state->pc + WC_CURSH_SKIP(state->pc[-1]); |
|
363 |
|
364 /* Skip word only used for try/always */ |
|
365 state->pc++; |
|
366 |
|
367 if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob)) |
|
368 deletejob(jobtab + thisjob); |
|
369 cmdpush(CS_CURSH); |
|
370 execlist(state, 1, do_exec); |
|
371 cmdpop(); |
|
372 |
|
373 state->pc = end; |
|
374 |
|
375 return lastval; |
|
376 } |
|
377 |
|
378 /* execve after handling $_ and #! */ |
|
379 |
|
380 #define POUNDBANGLIMIT 64 |
|
381 |
|
382 /**/ |
|
383 static int |
|
384 zexecve(char *pth, char **argv) |
|
385 { |
|
386 int eno =0; |
|
387 #ifndef __SYMBIAN32__ |
|
388 static char buf[PATH_MAX * 2]; |
|
389 char **eep; |
|
390 |
|
391 unmetafy(pth, NULL); |
|
392 for (eep = argv; *eep; eep++) |
|
393 if (*eep != pth) |
|
394 unmetafy(*eep, NULL); |
|
395 buf[0] = '_'; |
|
396 buf[1] = '='; |
|
397 if (*pth == '/') |
|
398 strcpy(buf + 2, pth); |
|
399 else |
|
400 sprintf(buf + 2, "%s/%s", pwd, pth); |
|
401 zputenv(buf); |
|
402 closedumps(); |
|
403 execve(pth, argv, environ); |
|
404 |
|
405 /* If the execve returns (which in general shouldn't happen), * |
|
406 * then check for an errno equal to ENOEXEC. This errno is set * |
|
407 * if the process file has the appropriate access permission, * |
|
408 * but has an invalid magic number in its header. */ |
|
409 if ((eno = errno) == ENOEXEC) { |
|
410 char execvebuf[POUNDBANGLIMIT + 1], *ptr, *ptr2, *argv0; |
|
411 int fd, ct, t0; |
|
412 |
|
413 if ((fd = open(pth, O_RDONLY|O_NOCTTY)) >= 0) { |
|
414 argv0 = *argv; |
|
415 *argv = pth; |
|
416 ct = read(fd, execvebuf, POUNDBANGLIMIT); |
|
417 close(fd); |
|
418 if (ct > 0) { |
|
419 if (execvebuf[0] == '#') { |
|
420 if (execvebuf[1] == '!') { |
|
421 for (t0 = 0; t0 != ct; t0++) |
|
422 if (execvebuf[t0] == '\n') |
|
423 break; |
|
424 while (inblank(execvebuf[t0])) |
|
425 execvebuf[t0--] = '\0'; |
|
426 execvebuf[POUNDBANGLIMIT] = '\0'; |
|
427 for (ptr = execvebuf + 2; *ptr && *ptr == ' '; ptr++); |
|
428 for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++); |
|
429 if (*ptr) { |
|
430 *ptr = '\0'; |
|
431 argv[-2] = ptr2; |
|
432 argv[-1] = ptr + 1; |
|
433 execve(ptr2, argv - 2, environ); |
|
434 } else { |
|
435 argv[-1] = ptr2; |
|
436 execve(ptr2, argv - 1, environ); |
|
437 } |
|
438 } else { |
|
439 argv[-1] = "sh"; |
|
440 execve("/bin/sh", argv - 1, environ); |
|
441 } |
|
442 } else { |
|
443 for (t0 = 0; t0 != ct; t0++) |
|
444 if (!execvebuf[t0]) |
|
445 break; |
|
446 if (t0 == ct) { |
|
447 argv[-1] = "sh"; |
|
448 execve("/bin/sh", argv - 1, environ); |
|
449 } |
|
450 } |
|
451 } else |
|
452 eno = errno; |
|
453 *argv = argv0; |
|
454 } else |
|
455 eno = errno; |
|
456 } |
|
457 /* restore the original arguments and path but do not bother with * |
|
458 * null characters as these cannot be passed to external commands * |
|
459 * anyway. So the result is truncated at the first null char. */ |
|
460 pth = metafy(pth, -1, META_NOALLOC); |
|
461 for (eep = argv; *eep; eep++) |
|
462 if (*eep != pth) |
|
463 (void) metafy(*eep, -1, META_NOALLOC); |
|
464 #endif//__SYMBIAN32__ |
|
465 |
|
466 return eno; |
|
467 } |
|
468 |
|
469 #define MAXCMDLEN (PATH_MAX*4) |
|
470 |
|
471 /* test whether we really want to believe the error number */ |
|
472 |
|
473 /**/ |
|
474 static int |
|
475 isgooderr(int e, char *dir) |
|
476 { |
|
477 /* |
|
478 * Maybe the directory was unreadable, or maybe it wasn't |
|
479 * even a directory. |
|
480 */ |
|
481 return ((e != EACCES || !access(dir, X_OK)) && |
|
482 e != ENOENT && e != ENOTDIR); |
|
483 } |
|
484 |
|
485 /* execute an external command */ |
|
486 |
|
487 /**/ |
|
488 void |
|
489 execute(UNUSED(Cmdnam cmdname), int dash, int defpath) |
|
490 { |
|
491 Cmdnam cn; |
|
492 char buf[MAXCMDLEN], buf2[MAXCMDLEN]; |
|
493 char *s, *z, *arg0; |
|
494 char **argv, **pp; |
|
495 int eno = 0, ee; |
|
496 |
|
497 arg0 = (char *) peekfirst(args); |
|
498 if (isset(RESTRICTED) && (strchr(arg0, '/') || defpath)) { |
|
499 zerr("%s: restricted", arg0, 0); |
|
500 _exit(1); |
|
501 } |
|
502 |
|
503 /* If the parameter STTY is set in the command's environment, * |
|
504 * we first run the stty command with the value of this * |
|
505 * parameter as it arguments. */ |
|
506 if ((s = STTYval) && isatty(0) && (GETPGRP() == getpid())) { |
|
507 LinkList exargs = args; |
|
508 char *t = tricat("stty", " ", s); |
|
509 |
|
510 STTYval = 0; /* this prevents infinite recursion */ |
|
511 zsfree(s); |
|
512 args = NULL; |
|
513 execstring(t, 1, 0); |
|
514 zsfree(t); |
|
515 args = exargs; |
|
516 } else if (s) { |
|
517 STTYval = 0; |
|
518 zsfree(s); |
|
519 } |
|
520 |
|
521 /* If ARGV0 is in the commands environment, we use * |
|
522 * that as argv[0] for this external command */ |
|
523 if (unset(RESTRICTED) && (z = zgetenv("ARGV0"))) { |
|
524 setdata(firstnode(args), (void *) ztrdup(z)); |
|
525 delenvvalue(z - 6); |
|
526 } else if (dash) { |
|
527 /* Else if the pre-command `-' was given, we add `-' * |
|
528 * to the front of argv[0] for this command. */ |
|
529 sprintf(buf2, "-%s", arg0); |
|
530 setdata(firstnode(args), (void *) ztrdup(buf2)); |
|
531 } |
|
532 |
|
533 argv = makecline(args); |
|
534 closem(3); |
|
535 child_unblock(); |
|
536 if ((int) strlen(arg0) >= PATH_MAX) { |
|
537 zerr("command too long: %s", arg0, 0); |
|
538 _exit(1); |
|
539 } |
|
540 for (s = arg0; *s; s++) |
|
541 if (*s == '/') { |
|
542 errno = zexecve(arg0, argv); |
|
543 if (arg0 == s || unset(PATHDIRS) || |
|
544 (arg0[0] == '.' && (arg0 + 1 == s || |
|
545 (arg0[1] == '.' && arg0 + 2 == s)))) { |
|
546 zerr("%e: %s", arg0, errno); |
|
547 _exit((errno == EACCES || errno == ENOEXEC) ? 126 : 127); |
|
548 } |
|
549 break; |
|
550 } |
|
551 |
|
552 /* for command -p, search the default path */ |
|
553 if (defpath) { |
|
554 char *s, pbuf[PATH_MAX]; |
|
555 char *dptr, *pe, *ps = DEFAULT_PATH; |
|
556 |
|
557 for(;ps;ps = pe ? pe+1 : NULL) { |
|
558 pe = strchr(ps, ':'); |
|
559 if (*ps == '/') { |
|
560 s = pbuf; |
|
561 if (pe) |
|
562 struncpy(&s, ps, pe-ps); |
|
563 else |
|
564 strucpy(&s, ps); |
|
565 *s++ = '/'; |
|
566 if ((s - pbuf) + strlen(arg0) >= PATH_MAX) |
|
567 continue; |
|
568 strucpy(&s, arg0); |
|
569 if (iscom(pbuf)) |
|
570 break; |
|
571 } |
|
572 } |
|
573 |
|
574 if (!ps) { |
|
575 zerr("command not found: %s", arg0, 0); |
|
576 _exit(127); |
|
577 } |
|
578 |
|
579 ee = zexecve(pbuf, argv); |
|
580 |
|
581 if ((dptr = strrchr(pbuf, '/'))) |
|
582 *dptr = '\0'; |
|
583 if (isgooderr(ee, *pbuf ? pbuf : "/")) |
|
584 eno = ee; |
|
585 |
|
586 } else { |
|
587 |
|
588 if ((cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0))) { |
|
589 char nn[PATH_MAX], *dptr; |
|
590 |
|
591 if (cn->flags & HASHED) |
|
592 strcpy(nn, cn->u.cmd); |
|
593 else { |
|
594 for (pp = path; pp < cn->u.name; pp++) |
|
595 if (!**pp || (**pp == '.' && (*pp)[1] == '\0')) { |
|
596 ee = zexecve(arg0, argv); |
|
597 if (isgooderr(ee, *pp)) |
|
598 eno = ee; |
|
599 } else if (**pp != '/') { |
|
600 z = buf; |
|
601 strucpy(&z, *pp); |
|
602 *z++ = '/'; |
|
603 strcpy(z, arg0); |
|
604 ee = zexecve(buf, argv); |
|
605 if (isgooderr(ee, *pp)) |
|
606 eno = ee; |
|
607 } |
|
608 strcpy(nn, cn->u.name ? *(cn->u.name) : ""); |
|
609 strcat(nn, "/"); |
|
610 strcat(nn, cn->nam); |
|
611 } |
|
612 ee = zexecve(nn, argv); |
|
613 |
|
614 if ((dptr = strrchr(nn, '/'))) |
|
615 *dptr = '\0'; |
|
616 if (isgooderr(ee, *nn ? nn : "/")) |
|
617 eno = ee; |
|
618 } |
|
619 for (pp = path; *pp; pp++) |
|
620 if (!(*pp)[0] || ((*pp)[0] == '.' && !(*pp)[1])) { |
|
621 ee = zexecve(arg0, argv); |
|
622 if (isgooderr(ee, *pp)) |
|
623 eno = ee; |
|
624 } else { |
|
625 z = buf; |
|
626 strucpy(&z, *pp); |
|
627 *z++ = '/'; |
|
628 strcpy(z, arg0); |
|
629 ee = zexecve(buf, argv); |
|
630 if (isgooderr(ee, *pp)) |
|
631 eno = ee; |
|
632 } |
|
633 } |
|
634 |
|
635 if (eno) |
|
636 zerr("%e: %s", arg0, eno); |
|
637 else |
|
638 zerr("command not found: %s", arg0, 0); |
|
639 _exit((eno == EACCES || eno == ENOEXEC) ? 126 : 127); |
|
640 } |
|
641 |
|
642 #define RET_IF_COM(X) { if (iscom(X)) return docopy ? dupstring(X) : arg0; } |
|
643 |
|
644 /* |
|
645 * Get the full pathname of an external command. |
|
646 * If the second argument is zero, return the first argument if found; |
|
647 * if non-zero, return the path using heap memory. (RET_IF_COM(X), above). |
|
648 */ |
|
649 |
|
650 /**/ |
|
651 mod_export char * |
|
652 findcmd(char *arg0, int docopy) |
|
653 { |
|
654 char **pp; |
|
655 char *z, *s, buf[MAXCMDLEN]; |
|
656 Cmdnam cn; |
|
657 |
|
658 cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0); |
|
659 if (!cn && isset(HASHCMDS)) |
|
660 cn = hashcmd(arg0, path); |
|
661 if ((int) strlen(arg0) > PATH_MAX) |
|
662 return NULL; |
|
663 for (s = arg0; *s; s++) |
|
664 if (*s == '/') { |
|
665 RET_IF_COM(arg0); |
|
666 if (arg0 == s || unset(PATHDIRS)) { |
|
667 return NULL; |
|
668 } |
|
669 break; |
|
670 } |
|
671 if (cn) { |
|
672 char nn[PATH_MAX]; |
|
673 |
|
674 if (cn->flags & HASHED) |
|
675 strcpy(nn, cn->u.cmd); |
|
676 else { |
|
677 for (pp = path; pp < cn->u.name; pp++) |
|
678 if (**pp != '/') { |
|
679 z = buf; |
|
680 if (**pp) { |
|
681 strucpy(&z, *pp); |
|
682 *z++ = '/'; |
|
683 } |
|
684 strcpy(z, arg0); |
|
685 RET_IF_COM(buf); |
|
686 } |
|
687 strcpy(nn, cn->u.name ? *(cn->u.name) : ""); |
|
688 strcat(nn, "/"); |
|
689 strcat(nn, cn->nam); |
|
690 } |
|
691 RET_IF_COM(nn); |
|
692 } |
|
693 for (pp = path; *pp; pp++) { |
|
694 z = buf; |
|
695 if (**pp) { |
|
696 strucpy(&z, *pp); |
|
697 *z++ = '/'; |
|
698 } |
|
699 strcpy(z, arg0); |
|
700 RET_IF_COM(buf); |
|
701 } |
|
702 return NULL; |
|
703 } |
|
704 |
|
705 /**/ |
|
706 int |
|
707 iscom(char *s) |
|
708 { |
|
709 struct stat statbuf; |
|
710 char *us = unmeta(s); |
|
711 |
|
712 return (access(us, X_OK) == 0 && stat(us, &statbuf) >= 0 && |
|
713 S_ISREG(statbuf.st_mode)); |
|
714 } |
|
715 |
|
716 /**/ |
|
717 int |
|
718 isreallycom(Cmdnam cn) |
|
719 { |
|
720 char fullnam[MAXCMDLEN]; |
|
721 |
|
722 if (cn->flags & HASHED) |
|
723 strcpy(fullnam, cn->u.cmd); |
|
724 else if (!cn->u.name) |
|
725 return 0; |
|
726 else { |
|
727 strcpy(fullnam, *(cn->u.name)); |
|
728 strcat(fullnam, "/"); |
|
729 strcat(fullnam, cn->nam); |
|
730 } |
|
731 return iscom(fullnam); |
|
732 } |
|
733 |
|
734 /**/ |
|
735 int |
|
736 isrelative(char *s) |
|
737 { |
|
738 if (*s != '/') |
|
739 return 1; |
|
740 for (; *s; s++) |
|
741 if (*s == '.' && s[-1] == '/' && |
|
742 (s[1] == '/' || s[1] == '\0' || |
|
743 (s[1] == '.' && (s[2] == '/' || s[2] == '\0')))) |
|
744 return 1; |
|
745 return 0; |
|
746 } |
|
747 |
|
748 /**/ |
|
749 mod_export Cmdnam |
|
750 hashcmd(char *arg0, char **pp) |
|
751 { |
|
752 Cmdnam cn; |
|
753 char *s, buf[PATH_MAX]; |
|
754 char **pq; |
|
755 |
|
756 for (; *pp; pp++) |
|
757 if (**pp == '/') { |
|
758 s = buf; |
|
759 strucpy(&s, *pp); |
|
760 *s++ = '/'; |
|
761 if ((s - buf) + strlen(arg0) >= PATH_MAX) |
|
762 continue; |
|
763 strcpy(s, arg0); |
|
764 if (iscom(buf)) |
|
765 break; |
|
766 } |
|
767 |
|
768 if (!*pp) |
|
769 return NULL; |
|
770 |
|
771 cn = (Cmdnam) zshcalloc(sizeof *cn); |
|
772 cn->flags = 0; |
|
773 cn->u.name = pp; |
|
774 cmdnamtab->addnode(cmdnamtab, ztrdup(arg0), cn); |
|
775 |
|
776 if (isset(HASHDIRS)) { |
|
777 for (pq = pathchecked; pq <= pp; pq++) |
|
778 hashdir(pq); |
|
779 pathchecked = pp + 1; |
|
780 } |
|
781 |
|
782 return cn; |
|
783 } |
|
784 |
|
785 /* execute a string */ |
|
786 |
|
787 /**/ |
|
788 mod_export void |
|
789 execstring(char *s, int dont_change_job, int exiting) |
|
790 { |
|
791 Eprog prog; |
|
792 |
|
793 pushheap(); |
|
794 if ((prog = parse_string(s))) |
|
795 execode(prog, dont_change_job, exiting); |
|
796 popheap(); |
|
797 } |
|
798 |
|
799 |
|
800 #ifdef __SYMBIAN32__ |
|
801 mod_export |
|
802 void* execode_wrap(void* any) |
|
803 { |
|
804 st_exec *st=(st_exec*)any; |
|
805 if(st) |
|
806 execode(st->p, st->dont_change_job, st->exiting); |
|
807 return NULL; |
|
808 } |
|
809 #endif //__SYMBIAN32__ |
|
810 |
|
811 /**/ |
|
812 mod_export void |
|
813 execode(Eprog p, int dont_change_job, int exiting) |
|
814 { |
|
815 struct estate s; |
|
816 |
|
817 s.prog = p; |
|
818 s.pc = p->prog; |
|
819 s.strs = p->strs; |
|
820 useeprog(p); /* Mark as in use */ |
|
821 |
|
822 execlist(&s, dont_change_job, exiting); |
|
823 |
|
824 freeeprog(p); /* Free if now unused */ |
|
825 } |
|
826 |
|
827 /* Execute a simplified command. This is used to execute things that |
|
828 * will run completely in the shell, so that we can by-pass all that |
|
829 * nasty job-handling and redirection stuff in execpline and execcmd. */ |
|
830 |
|
831 /**/ |
|
832 static int |
|
833 execsimple(Estate state) |
|
834 { |
|
835 wordcode code = *state->pc++; |
|
836 int lv; |
|
837 |
|
838 if (errflag) |
|
839 return (lastval = 1); |
|
840 |
|
841 /* In evaluated traps, don't modify the line number. */ |
|
842 if ((!intrap || trapisfunc) && !ineval && code) |
|
843 lineno = code - 1; |
|
844 |
|
845 code = wc_code(*state->pc++); |
|
846 |
|
847 if (code == WC_ASSIGN) { |
|
848 cmdoutval = 0; |
|
849 addvars(state, state->pc - 1, 0); |
|
850 if (isset(XTRACE)) { |
|
851 fputc('\n', xtrerr); |
|
852 fflush(xtrerr); |
|
853 } |
|
854 lv = (lastval ? lastval : cmdoutval); |
|
855 } else |
|
856 lv = (execfuncs[code - WC_CURSH])(state, 0); |
|
857 |
|
858 return lastval = lv; |
|
859 } |
|
860 |
|
861 /* Main routine for executing a list. * |
|
862 * exiting means that the (sub)shell we are in is a definite goner * |
|
863 * after the current list is finished, so we may be able to exec the * |
|
864 * last command directly instead of forking. If dont_change_job is * |
|
865 * nonzero, then restore the current job number after executing the * |
|
866 * list. */ |
|
867 |
|
868 /**/ |
|
869 void |
|
870 execlist(Estate state, int dont_change_job, int exiting) |
|
871 { |
|
872 static int donetrap; |
|
873 Wordcode next; |
|
874 wordcode code; |
|
875 int ret, cj, csp, ltype; |
|
876 int old_pline_level, old_list_pipe, oldlineno; |
|
877 /* |
|
878 * ERREXIT only forces the shell to exit if the last command in a && |
|
879 * or || fails. This is the case even if an earlier command is a |
|
880 * shell function or other current shell structure, so we have to set |
|
881 * noerrexit here if the sublist is not of type END. |
|
882 */ |
|
883 int oldnoerrexit = noerrexit; |
|
884 |
|
885 cj = thisjob; |
|
886 old_pline_level = pline_level; |
|
887 old_list_pipe = list_pipe; |
|
888 oldlineno = lineno; |
|
889 |
|
890 if (sourcelevel && unset(SHINSTDIN)) |
|
891 pline_level = list_pipe = 0; |
|
892 |
|
893 /* Loop over all sets of comands separated by newline, * |
|
894 * semi-colon or ampersand (`sublists'). */ |
|
895 code = *state->pc++; |
|
896 while (wc_code(code) == WC_LIST && !breaks && !retflag) { |
|
897 ltype = WC_LIST_TYPE(code); |
|
898 csp = cmdsp; |
|
899 |
|
900 if (ltype & Z_SIMPLE) { |
|
901 next = state->pc + WC_LIST_SKIP(code); |
|
902 execsimple(state); |
|
903 state->pc = next; |
|
904 goto sublist_done; |
|
905 } |
|
906 /* Reset donetrap: this ensures that a trap is only * |
|
907 * called once for each sublist that fails. */ |
|
908 donetrap = 0; |
|
909 |
|
910 /* Loop through code followed by &&, ||, or end of sublist. */ |
|
911 code = *state->pc++; |
|
912 while (wc_code(code) == WC_SUBLIST) { |
|
913 next = state->pc + WC_SUBLIST_SKIP(code); |
|
914 if (!oldnoerrexit) |
|
915 noerrexit = (WC_SUBLIST_TYPE(code) != WC_SUBLIST_END); |
|
916 switch (WC_SUBLIST_TYPE(code)) { |
|
917 case WC_SUBLIST_END: |
|
918 /* End of sublist; just execute, ignoring status. */ |
|
919 if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) |
|
920 execsimple(state); |
|
921 else |
|
922 execpline(state, code, ltype, (ltype & Z_END) && exiting); |
|
923 state->pc = next; |
|
924 goto sublist_done; |
|
925 break; |
|
926 case WC_SUBLIST_AND: |
|
927 /* If the return code is non-zero, we skip pipelines until * |
|
928 * we find a sublist followed by ORNEXT. */ |
|
929 if ((ret = ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ? |
|
930 execsimple(state) : |
|
931 execpline(state, code, Z_SYNC, 0)))) { |
|
932 state->pc = next; |
|
933 code = *state->pc++; |
|
934 next = state->pc + WC_SUBLIST_SKIP(code); |
|
935 while (wc_code(code) == WC_SUBLIST && |
|
936 WC_SUBLIST_TYPE(code) == WC_SUBLIST_AND) { |
|
937 state->pc = next; |
|
938 code = *state->pc++; |
|
939 next = state->pc + WC_SUBLIST_SKIP(code); |
|
940 } |
|
941 if (wc_code(code) != WC_SUBLIST) { |
|
942 /* We've skipped to the end of the list, not executing * |
|
943 * the final pipeline, so don't perform error handling * |
|
944 * for this sublist. */ |
|
945 donetrap = 1; |
|
946 goto sublist_done; |
|
947 } else if (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END) { |
|
948 donetrap = 1; |
|
949 /* |
|
950 * Treat this in the same way as if we reached |
|
951 * the end of the sublist normally. |
|
952 */ |
|
953 state->pc = next; |
|
954 goto sublist_done; |
|
955 } |
|
956 } |
|
957 cmdpush(CS_CMDAND); |
|
958 break; |
|
959 case WC_SUBLIST_OR: |
|
960 /* If the return code is zero, we skip pipelines until * |
|
961 * we find a sublist followed by ANDNEXT. */ |
|
962 if (!(ret = ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ? |
|
963 execsimple(state) : |
|
964 execpline(state, code, Z_SYNC, 0)))) { |
|
965 state->pc = next; |
|
966 code = *state->pc++; |
|
967 next = state->pc + WC_SUBLIST_SKIP(code); |
|
968 while (wc_code(code) == WC_SUBLIST && |
|
969 WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR) { |
|
970 state->pc = next; |
|
971 code = *state->pc++; |
|
972 next = state->pc + WC_SUBLIST_SKIP(code); |
|
973 } |
|
974 if (wc_code(code) != WC_SUBLIST) { |
|
975 /* We've skipped to the end of the list, not executing * |
|
976 * the final pipeline, so don't perform error handling * |
|
977 * for this sublist. */ |
|
978 donetrap = 1; |
|
979 goto sublist_done; |
|
980 } else if (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END) { |
|
981 donetrap = 1; |
|
982 /* |
|
983 * Treat this in the same way as if we reached |
|
984 * the end of the sublist normally. |
|
985 */ |
|
986 state->pc = next; |
|
987 goto sublist_done; |
|
988 } |
|
989 } |
|
990 cmdpush(CS_CMDOR); |
|
991 break; |
|
992 } |
|
993 state->pc = next; |
|
994 code = *state->pc++; |
|
995 } |
|
996 state->pc--; |
|
997 sublist_done: |
|
998 |
|
999 noerrexit = oldnoerrexit; |
|
1000 |
|
1001 if (sigtrapped[SIGDEBUG]) { |
|
1002 exiting = donetrap; |
|
1003 ret = lastval; |
|
1004 dotrap(SIGDEBUG); |
|
1005 lastval = ret; |
|
1006 donetrap = exiting; |
|
1007 noerrexit = oldnoerrexit; |
|
1008 } |
|
1009 |
|
1010 cmdsp = csp; |
|
1011 |
|
1012 /* Check whether we are suppressing traps/errexit * |
|
1013 * (typically in init scripts) and if we haven't * |
|
1014 * already performed them for this sublist. */ |
|
1015 if (!noerrexit && !donetrap) { |
|
1016 if (sigtrapped[SIGZERR] && lastval) { |
|
1017 dotrap(SIGZERR); |
|
1018 donetrap = 1; |
|
1019 } |
|
1020 if (lastval) { |
|
1021 int errreturn = isset(ERRRETURN) && |
|
1022 (isset(INTERACTIVE) || locallevel || sourcelevel); |
|
1023 int errexit = isset(ERREXIT) || |
|
1024 (isset(ERRRETURN) && !errreturn); |
|
1025 if (errexit) { |
|
1026 if (sigtrapped[SIGEXIT]) |
|
1027 dotrap(SIGEXIT); |
|
1028 if (mypid != getpid()) |
|
1029 _exit(lastval); |
|
1030 else |
|
1031 exit(lastval); |
|
1032 } |
|
1033 if (errreturn) { |
|
1034 retflag = 1; |
|
1035 breaks = loops; |
|
1036 } |
|
1037 } |
|
1038 } |
|
1039 if (ltype & Z_END) |
|
1040 break; |
|
1041 code = *state->pc++; |
|
1042 } |
|
1043 pline_level = old_pline_level; |
|
1044 list_pipe = old_list_pipe; |
|
1045 lineno = oldlineno; |
|
1046 if (dont_change_job) |
|
1047 thisjob = cj; |
|
1048 } |
|
1049 |
|
1050 /* Execute a pipeline. * |
|
1051 * last1 is a flag that this command is the last command in a shell * |
|
1052 * that is about to exit, so we can exec instead of forking. It gets * |
|
1053 * passed all the way down to execcmd() which actually makes the * |
|
1054 * decision. A 0 is always passed if the command is not the last in * |
|
1055 * the pipeline. This function assumes that the sublist is not NULL. * |
|
1056 * If last1 is zero but the command is at the end of a pipeline, we * |
|
1057 * pass 2 down to execcmd(). * |
|
1058 */ |
|
1059 |
|
1060 /**/ |
|
1061 static int |
|
1062 execpline(Estate state, wordcode slcode, int how, int last1) |
|
1063 { |
|
1064 int ipipe[2], opipe[2]; |
|
1065 int pj, newjob; |
|
1066 int old_simple_pline = simple_pline; |
|
1067 int slflags = WC_SUBLIST_FLAGS(slcode); |
|
1068 wordcode code = *state->pc++; |
|
1069 static int lastwj, lpforked; |
|
1070 |
|
1071 if (wc_code(code) != WC_PIPE) |
|
1072 return lastval = (slflags & WC_SUBLIST_NOT) != 0; |
|
1073 else if (slflags & WC_SUBLIST_NOT) |
|
1074 last1 = 0; |
|
1075 |
|
1076 pj = thisjob; |
|
1077 ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0; |
|
1078 child_block(); |
|
1079 |
|
1080 /* |
|
1081 * Get free entry in job table and initialize it. |
|
1082 * This is currently the only call to initjob(), so this |
|
1083 * is also the only place where we can expand the job table |
|
1084 * under us. |
|
1085 */ |
|
1086 if ((thisjob = newjob = initjob()) == -1) { |
|
1087 child_unblock(); |
|
1088 return 1; |
|
1089 } |
|
1090 if (how & Z_TIMED) |
|
1091 jobtab[thisjob].stat |= STAT_TIMED; |
|
1092 |
|
1093 if (slflags & WC_SUBLIST_COPROC) { |
|
1094 how = Z_ASYNC; |
|
1095 if (coprocin >= 0) { |
|
1096 zclose(coprocin); |
|
1097 zclose(coprocout); |
|
1098 } |
|
1099 mpipe(ipipe); |
|
1100 mpipe(opipe); |
|
1101 coprocin = ipipe[0]; |
|
1102 coprocout = opipe[1]; |
|
1103 fdtable[coprocin] = fdtable[coprocout] = 0; |
|
1104 } |
|
1105 /* This used to set list_pipe_pid=0 unconditionally, but in things |
|
1106 * like `ls|if true; then sleep 20; cat; fi' where the sleep was |
|
1107 * stopped, the top-level execpline() didn't get the pid for the |
|
1108 * sub-shell because it was overwritten. */ |
|
1109 if (!pline_level++) { |
|
1110 list_pipe_pid = 0; |
|
1111 nowait = 0; |
|
1112 simple_pline = (WC_PIPE_TYPE(code) == WC_PIPE_END); |
|
1113 list_pipe_job = newjob; |
|
1114 } |
|
1115 lastwj = lpforked = 0; |
|
1116 execpline2(state, code, how, opipe[0], ipipe[1], last1); |
|
1117 pline_level--; |
|
1118 if (how & Z_ASYNC) { |
|
1119 lastwj = newjob; |
|
1120 |
|
1121 if (thisjob == list_pipe_job) |
|
1122 list_pipe_job = 0; |
|
1123 jobtab[thisjob].stat |= STAT_NOSTTY; |
|
1124 if (slflags & WC_SUBLIST_COPROC) { |
|
1125 zclose(ipipe[1]); |
|
1126 zclose(opipe[0]); |
|
1127 } |
|
1128 if (how & Z_DISOWN) { |
|
1129 deletejob(jobtab + thisjob); |
|
1130 thisjob = -1; |
|
1131 } |
|
1132 else |
|
1133 spawnjob(); |
|
1134 child_unblock(); |
|
1135 return 0; |
|
1136 } else { |
|
1137 if (newjob != lastwj) { |
|
1138 Job jn = jobtab + newjob; |
|
1139 int updated; |
|
1140 |
|
1141 if (newjob == list_pipe_job && list_pipe_child) |
|
1142 _exit(0); |
|
1143 |
|
1144 lastwj = thisjob = newjob; |
|
1145 |
|
1146 if (list_pipe || (pline_level && !(how & Z_TIMED))) |
|
1147 jn->stat |= STAT_NOPRINT; |
|
1148 |
|
1149 if (nowait) { |
|
1150 if(!pline_level) { |
|
1151 struct process *pn, *qn; |
|
1152 |
|
1153 curjob = newjob; |
|
1154 DPUTS(!list_pipe_pid, "invalid list_pipe_pid"); |
|
1155 addproc(list_pipe_pid, list_pipe_text, 0, |
|
1156 &list_pipe_start); |
|
1157 |
|
1158 /* If the super-job contains only the sub-shell, the |
|
1159 sub-shell is the group leader. */ |
|
1160 if (!jn->procs->next || lpforked == 2) { |
|
1161 jn->gleader = list_pipe_pid; |
|
1162 jn->stat |= STAT_SUBLEADER; |
|
1163 } |
|
1164 for (pn = jobtab[jn->other].procs; pn; pn = pn->next) |
|
1165 if (WIFSTOPPED(pn->status)) |
|
1166 break; |
|
1167 |
|
1168 if (pn) { |
|
1169 for (qn = jn->procs; qn->next; qn = qn->next); |
|
1170 qn->status = pn->status; |
|
1171 } |
|
1172 |
|
1173 jn->stat &= ~(STAT_DONE | STAT_NOPRINT); |
|
1174 jn->stat |= STAT_STOPPED | STAT_CHANGED | STAT_LOCKED; |
|
1175 printjob(jn, !!isset(LONGLISTJOBS), 1); |
|
1176 } |
|
1177 else if (newjob != list_pipe_job) |
|
1178 deletejob(jn); |
|
1179 else |
|
1180 lastwj = -1; |
|
1181 } |
|
1182 |
|
1183 errbrk_saved = 0; |
|
1184 for (; !nowait;) { |
|
1185 if (list_pipe_child) { |
|
1186 jn->stat |= STAT_NOPRINT; |
|
1187 makerunning(jn); |
|
1188 } |
|
1189 if (!(jn->stat & STAT_LOCKED)) { |
|
1190 updated = hasprocs(thisjob); |
|
1191 waitjobs(); |
|
1192 child_block(); |
|
1193 } else |
|
1194 updated = 0; |
|
1195 if (!updated && |
|
1196 list_pipe_job && hasprocs(list_pipe_job) && |
|
1197 !(jobtab[list_pipe_job].stat & STAT_STOPPED)) { |
|
1198 child_unblock(); |
|
1199 child_block(); |
|
1200 } |
|
1201 if (list_pipe_child && |
|
1202 jn->stat & STAT_DONE && |
|
1203 lastval2 & 0200) |
|
1204 killpg(mypgrp, lastval2 & ~0200); |
|
1205 if (!list_pipe_child && !lpforked && !subsh && jobbing && |
|
1206 (list_pipe || last1 || pline_level) && |
|
1207 ((jn->stat & STAT_STOPPED) || |
|
1208 (list_pipe_job && pline_level && |
|
1209 (jobtab[list_pipe_job].stat & STAT_STOPPED)))) { |
|
1210 #ifndef __SYMBIAN32__ |
|
1211 pid_t pid; |
|
1212 int synch[2]; |
|
1213 struct timeval bgtime; |
|
1214 |
|
1215 pipe(synch); |
|
1216 |
|
1217 if ((pid = zfork(&bgtime)) == -1) { |
|
1218 trashzle(); |
|
1219 close(synch[0]); |
|
1220 close(synch[1]); |
|
1221 fprintf(stderr, "zsh: job can't be suspended\n"); |
|
1222 fflush(stderr); |
|
1223 makerunning(jn); |
|
1224 killjb(jn, SIGCONT); |
|
1225 thisjob = newjob; |
|
1226 } |
|
1227 else if (pid) { |
|
1228 char dummy; |
|
1229 |
|
1230 lpforked = |
|
1231 (killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1); |
|
1232 list_pipe_pid = pid; |
|
1233 list_pipe_start = bgtime; |
|
1234 nowait = errflag = 1; |
|
1235 breaks = loops; |
|
1236 close(synch[1]); |
|
1237 read(synch[0], &dummy, 1); |
|
1238 close(synch[0]); |
|
1239 /* If this job has finished, we leave it as a |
|
1240 * normal (non-super-) job. */ |
|
1241 if (!(jn->stat & STAT_DONE)) { |
|
1242 jobtab[list_pipe_job].other = newjob; |
|
1243 jobtab[list_pipe_job].stat |= STAT_SUPERJOB; |
|
1244 jn->stat |= STAT_SUBJOB | STAT_NOPRINT; |
|
1245 jn->other = pid; |
|
1246 } |
|
1247 if ((list_pipe || last1) && hasprocs(list_pipe_job)) |
|
1248 killpg(jobtab[list_pipe_job].gleader, SIGSTOP); |
|
1249 break; |
|
1250 } |
|
1251 else { |
|
1252 close(synch[0]); |
|
1253 entersubsh(Z_ASYNC, 0, 0, 0); |
|
1254 if (jobtab[list_pipe_job].procs) { |
|
1255 if (setpgrp(0L, mypgrp = jobtab[list_pipe_job].gleader) |
|
1256 == -1) { |
|
1257 setpgrp(0L, mypgrp = getpid()); |
|
1258 } |
|
1259 } else |
|
1260 setpgrp(0L, mypgrp = getpid()); |
|
1261 close(synch[1]); |
|
1262 kill(getpid(), SIGSTOP); |
|
1263 list_pipe = 0; |
|
1264 list_pipe_child = 1; |
|
1265 opts[INTERACTIVE] = 0; |
|
1266 if (errbrk_saved) { |
|
1267 errflag = prev_errflag; |
|
1268 breaks = prev_breaks; |
|
1269 } |
|
1270 break; |
|
1271 } |
|
1272 #else |
|
1273 if ((list_pipe || last1) && hasprocs(list_pipe_job)) |
|
1274 killpg(jobtab[list_pipe_job].gleader, SIGSTOP); |
|
1275 break; |
|
1276 #endif // __SYMBIAN32__ |
|
1277 } |
|
1278 else if (subsh && jn->stat & STAT_STOPPED) |
|
1279 thisjob = newjob; |
|
1280 else |
|
1281 break; |
|
1282 } |
|
1283 child_unblock(); |
|
1284 |
|
1285 if (list_pipe && (lastval & 0200) && pj >= 0 && |
|
1286 (!(jn->stat & STAT_INUSE) || (jn->stat & STAT_DONE))) { |
|
1287 deletejob(jn); |
|
1288 jn = jobtab + pj; |
|
1289 if (jn->gleader) |
|
1290 killjb(jn, lastval & ~0200); |
|
1291 } |
|
1292 if (list_pipe_child || |
|
1293 ((jn->stat & STAT_DONE) && |
|
1294 (list_pipe || (pline_level && !(jn->stat & STAT_SUBJOB))))) |
|
1295 deletejob(jn); |
|
1296 thisjob = pj; |
|
1297 |
|
1298 } |
|
1299 if (slflags & WC_SUBLIST_NOT) |
|
1300 lastval = !lastval; |
|
1301 } |
|
1302 if (!pline_level) |
|
1303 simple_pline = old_simple_pline; |
|
1304 return lastval; |
|
1305 } |
|
1306 |
|
1307 static int subsh_close = -1; |
|
1308 |
|
1309 /* execute pipeline. This function assumes the `pline' is not NULL. */ |
|
1310 |
|
1311 /**/ |
|
1312 static void |
|
1313 execpline2(Estate state, wordcode pcode, |
|
1314 int how, int input, int output, int last1) |
|
1315 { |
|
1316 int pipes[2]; |
|
1317 if (breaks || retflag) |
|
1318 return; |
|
1319 |
|
1320 /* In evaluated traps, don't modify the line number. */ |
|
1321 if ((!intrap || trapisfunc) && !ineval && WC_PIPE_LINENO(pcode)) |
|
1322 lineno = WC_PIPE_LINENO(pcode) - 1; |
|
1323 |
|
1324 if (pline_level == 1) { |
|
1325 if ((how & Z_ASYNC) || (!sfcontext && !sourcelevel)) |
|
1326 strcpy(list_pipe_text, |
|
1327 getjobtext(state->prog, |
|
1328 state->pc + (WC_PIPE_TYPE(pcode) == WC_PIPE_END ? |
|
1329 0 : 1))); |
|
1330 else |
|
1331 list_pipe_text[0] = '\0'; |
|
1332 } |
|
1333 if (WC_PIPE_TYPE(pcode) == WC_PIPE_END) |
|
1334 |
|
1335 #ifndef __SYMBIAN32__ |
|
1336 execcmd(state, input, output, how, last1 ? 1 : 2); |
|
1337 #else |
|
1338 execcmd(state, input, 0, how, last1 ? 1 : 2); |
|
1339 #endif |
|
1340 else { |
|
1341 int old_list_pipe = list_pipe; |
|
1342 Wordcode next = state->pc + (*state->pc), pc; |
|
1343 wordcode code; |
|
1344 |
|
1345 state->pc++; |
|
1346 for (pc = state->pc; wc_code(code = *pc) == WC_REDIR; pc += 3); |
|
1347 |
|
1348 mpipe(pipes); |
|
1349 /* if we are doing "foo | bar" where foo is a current * |
|
1350 * shell command, do foo in a subshell and do the * |
|
1351 * rest of the pipeline in the current shell. */ |
|
1352 if (wc_code(code) >= WC_CURSH && (how & Z_SYNC)) { |
|
1353 #ifndef __SYMBIAN32__ |
|
1354 |
|
1355 int synch[2]; |
|
1356 pid_t pid; |
|
1357 struct timeval bgtime; |
|
1358 |
|
1359 pipe(synch); |
|
1360 if ((pid = zfork(&bgtime)) == -1) { |
|
1361 close(synch[0]); |
|
1362 close(synch[1]); |
|
1363 } else if (pid) { |
|
1364 char dummy, *text; |
|
1365 |
|
1366 text = getjobtext(state->prog, state->pc); |
|
1367 addproc(pid, text, 0, &bgtime); |
|
1368 close(synch[1]); |
|
1369 read(synch[0], &dummy, 1); |
|
1370 close(synch[0]); |
|
1371 } else { |
|
1372 zclose(pipes[0]); |
|
1373 close(synch[0]); |
|
1374 entersubsh(how, 2, 0, 0); |
|
1375 close(synch[1]); |
|
1376 execcmd(state, input, pipes[1], how, 0); |
|
1377 _exit(lastval); |
|
1378 } |
|
1379 #else |
|
1380 execcmd(state, input, pipes[1], how, 0); |
|
1381 #endif//__SYMBIAN32__ |
|
1382 } else { |
|
1383 /* otherwise just do the pipeline normally. */ |
|
1384 #ifndef __SYMBIAN32__ |
|
1385 subsh_close = pipes[0]; |
|
1386 execcmd(state, input, pipes[1], how, 0); |
|
1387 #else |
|
1388 execcmd(state, 1, 1, how, 0); |
|
1389 #endif |
|
1390 } |
|
1391 #ifndef __SYMBIAN32__ |
|
1392 zclose(pipes[1]); |
|
1393 #endif |
|
1394 state->pc = next; |
|
1395 |
|
1396 /* if another execpline() is invoked because the command is * |
|
1397 * a list it must know that we're already in a pipeline */ |
|
1398 cmdpush(CS_PIPE); |
|
1399 list_pipe = 1; |
|
1400 #ifndef __SYMBIAN32__ |
|
1401 execpline2(state, *state->pc++, how, pipes[0], output, last1); |
|
1402 #else |
|
1403 execpline2(state, *state->pc++, how, 1, output, last1); |
|
1404 #endif |
|
1405 list_pipe = old_list_pipe; |
|
1406 cmdpop(); |
|
1407 #ifndef __SYMBIAN32__ |
|
1408 zclose(pipes[0]); |
|
1409 #endif |
|
1410 subsh_close = -1; |
|
1411 } |
|
1412 } |
|
1413 |
|
1414 /* make the argv array */ |
|
1415 |
|
1416 /**/ |
|
1417 static char ** |
|
1418 makecline(LinkList list) |
|
1419 { |
|
1420 LinkNode node; |
|
1421 char **argv, **ptr; |
|
1422 |
|
1423 /* A bigger argv is necessary for executing scripts */ |
|
1424 ptr = argv = 2 + (char **) hcalloc((countlinknodes(list) + 4) * |
|
1425 sizeof(char *)); |
|
1426 |
|
1427 if (isset(XTRACE)) { |
|
1428 if (!doneps4) |
|
1429 printprompt4(); |
|
1430 |
|
1431 for (node = firstnode(list); node; incnode(node)) { |
|
1432 *ptr++ = (char *)getdata(node); |
|
1433 quotedzputs(getdata(node), xtrerr); |
|
1434 if (nextnode(node)) |
|
1435 fputc(' ', xtrerr); |
|
1436 } |
|
1437 fputc('\n', xtrerr); |
|
1438 fflush(xtrerr); |
|
1439 } else { |
|
1440 for (node = firstnode(list); node; incnode(node)) |
|
1441 *ptr++ = (char *)getdata(node); |
|
1442 } |
|
1443 *ptr = NULL; |
|
1444 return (argv); |
|
1445 } |
|
1446 |
|
1447 /**/ |
|
1448 mod_export void |
|
1449 untokenize(char *s) |
|
1450 { |
|
1451 if (*s) { |
|
1452 int c; |
|
1453 |
|
1454 while ((c = *s++)) |
|
1455 if (itok(c)) { |
|
1456 char *p = s - 1; |
|
1457 |
|
1458 if (c != Nularg) |
|
1459 *p++ = ztokens[c - Pound]; |
|
1460 |
|
1461 while ((c = *s++)) { |
|
1462 if (itok(c)) { |
|
1463 if (c != Nularg) |
|
1464 *p++ = ztokens[c - Pound]; |
|
1465 } else |
|
1466 *p++ = c; |
|
1467 } |
|
1468 *p = '\0'; |
|
1469 break; |
|
1470 } |
|
1471 } |
|
1472 } |
|
1473 |
|
1474 /* Open a file for writing redirection */ |
|
1475 |
|
1476 /**/ |
|
1477 static int |
|
1478 clobber_open(struct redir *f) |
|
1479 { |
|
1480 struct stat buf; |
|
1481 int fd, oerrno; |
|
1482 |
|
1483 /* If clobbering, just open. */ |
|
1484 if (isset(CLOBBER) || IS_CLOBBER_REDIR(f->type)) |
|
1485 return open(unmeta(f->name), |
|
1486 O_WRONLY | O_CREAT | O_TRUNC | O_NOCTTY, 0666); |
|
1487 |
|
1488 /* If not clobbering, attempt to create file exclusively. */ |
|
1489 if ((fd = open(unmeta(f->name), |
|
1490 O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0666)) >= 0) |
|
1491 return fd; |
|
1492 |
|
1493 /* If that fails, we are still allowed to open non-regular files. * |
|
1494 * Try opening, and if it's a regular file then close it again * |
|
1495 * because we weren't supposed to open it. */ |
|
1496 oerrno = errno; |
|
1497 if ((fd = open(unmeta(f->name), O_WRONLY | O_NOCTTY)) != -1) { |
|
1498 if(!fstat(fd, &buf) && !S_ISREG(buf.st_mode)) |
|
1499 return fd; |
|
1500 close(fd); |
|
1501 } |
|
1502 errno = oerrno; |
|
1503 return -1; |
|
1504 } |
|
1505 |
|
1506 /* size of buffer for tee and cat processes */ |
|
1507 #define TCBUFSIZE 4092 |
|
1508 |
|
1509 /* close an multio (success) */ |
|
1510 |
|
1511 /**/ |
|
1512 static void |
|
1513 closemn(struct multio **mfds, int fd) |
|
1514 { |
|
1515 if (fd >= 0 && mfds[fd] && mfds[fd]->ct >= 2) { |
|
1516 struct multio *mn = mfds[fd]; |
|
1517 int i; |
|
1518 |
|
1519 #ifndef __SYMBIAN32__ |
|
1520 char buf[TCBUFSIZE]; |
|
1521 pid_t pid; |
|
1522 int len; |
|
1523 struct timeval bgtime; |
|
1524 |
|
1525 if ((pid = zfork(&bgtime))) { |
|
1526 for (i = 0; i < mn->ct; i++) |
|
1527 zclose(mn->fds[i]); |
|
1528 zclose(mn->pipe); |
|
1529 if (pid == -1) { |
|
1530 mfds[fd] = NULL; |
|
1531 return; |
|
1532 } |
|
1533 mn->ct = 1; |
|
1534 mn->fds[0] = fd; |
|
1535 addproc(pid, NULL, 1, &bgtime); |
|
1536 return; |
|
1537 } |
|
1538 /* pid == 0 */ |
|
1539 closeallelse(mn); |
|
1540 if (mn->rflag) { |
|
1541 /* tee process */ |
|
1542 while ((len = read(mn->pipe, buf, TCBUFSIZE)) != 0) { |
|
1543 if (len < 0) { |
|
1544 if (errno == EINTR) |
|
1545 continue; |
|
1546 else |
|
1547 break; |
|
1548 } |
|
1549 for (i = 0; i < mn->ct; i++) |
|
1550 write(mn->fds[i], buf, len); |
|
1551 } |
|
1552 } else { |
|
1553 /* cat process */ |
|
1554 for (i = 0; i < mn->ct; i++) |
|
1555 while ((len = read(mn->fds[i], buf, TCBUFSIZE)) != 0) { |
|
1556 if (len < 0) { |
|
1557 if (errno == EINTR) |
|
1558 continue; |
|
1559 else |
|
1560 break; |
|
1561 } |
|
1562 write(mn->pipe, buf, len); |
|
1563 } |
|
1564 } |
|
1565 _exit(0); |
|
1566 #else |
|
1567 for (i = 0; i < mn->ct; i++) |
|
1568 zclose(mn->fds[i]); |
|
1569 |
|
1570 zclose(mn->pipe); |
|
1571 mn->ct = 1; |
|
1572 mn->fds[0] = fd; |
|
1573 return; |
|
1574 #endif |
|
1575 } else if (fd >= 0) |
|
1576 mfds[fd] = NULL; |
|
1577 } |
|
1578 |
|
1579 /* close all the mnodes (failure) */ |
|
1580 |
|
1581 /**/ |
|
1582 static void |
|
1583 closemnodes(struct multio **mfds) |
|
1584 { |
|
1585 int i, j; |
|
1586 |
|
1587 for (i = 0; i < 10; i++) |
|
1588 if (mfds[i]) { |
|
1589 for (j = 0; j < mfds[i]->ct; j++) |
|
1590 zclose(mfds[i]->fds[j]); |
|
1591 mfds[i] = NULL; |
|
1592 } |
|
1593 } |
|
1594 |
|
1595 /**/ |
|
1596 static void |
|
1597 closeallelse(struct multio *mn) |
|
1598 { |
|
1599 int i, j; |
|
1600 long openmax; |
|
1601 |
|
1602 openmax = zopenmax(); |
|
1603 |
|
1604 for (i = 0; i < openmax; i++) |
|
1605 if (mn->pipe != i) { |
|
1606 for (j = 0; j < mn->ct; j++) |
|
1607 if (mn->fds[j] == i) |
|
1608 break; |
|
1609 if (j == mn->ct) |
|
1610 zclose(i); |
|
1611 } |
|
1612 } |
|
1613 |
|
1614 /* A multio is a list of fds associated with a certain fd. * |
|
1615 * Thus if you do "foo >bar >ble", the multio for fd 1 will have * |
|
1616 * two fds, the result of open("bar",...), and the result of * |
|
1617 * open("ble",....). */ |
|
1618 |
|
1619 /* Add a fd to an multio. fd1 must be < 10, and may be in any state. * |
|
1620 * fd2 must be open, and is `consumed' by this function. Note that * |
|
1621 * fd1 == fd2 is possible, and indicates that fd1 was really closed. * |
|
1622 * We effectively do `fd2 = movefd(fd2)' at the beginning of this * |
|
1623 * function, but in most cases we can avoid an extra dup by delaying * |
|
1624 * the movefd: we only >need< to move it if we're actually doing a * |
|
1625 * multiple redirection. */ |
|
1626 |
|
1627 /**/ |
|
1628 static void |
|
1629 addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag) |
|
1630 { |
|
1631 int pipes[2]; |
|
1632 if (!mfds[fd1] || unset(MULTIOS)) { |
|
1633 if(!mfds[fd1]) { /* starting a new multio */ |
|
1634 mfds[fd1] = (struct multio *) zhalloc(sizeof(struct multio)); |
|
1635 if (!forked && save[fd1] == -2) |
|
1636 save[fd1] = (fd1 == fd2) ? -1 : movefd(fd1); |
|
1637 } |
|
1638 redup(fd2, fd1); |
|
1639 mfds[fd1]->ct = 1; |
|
1640 mfds[fd1]->fds[0] = fd1; |
|
1641 mfds[fd1]->rflag = rflag; |
|
1642 } else { |
|
1643 if (mfds[fd1]->rflag != rflag) { |
|
1644 zerr("file mode mismatch on fd %d", NULL, fd1); |
|
1645 return; |
|
1646 } |
|
1647 if (mfds[fd1]->ct == 1) { /* split the stream */ |
|
1648 mfds[fd1]->fds[0] = movefd(fd1); |
|
1649 mfds[fd1]->fds[1] = movefd(fd2); |
|
1650 mpipe(pipes); |
|
1651 mfds[fd1]->pipe = pipes[1 - rflag]; |
|
1652 redup(pipes[rflag], fd1); |
|
1653 mfds[fd1]->ct = 2; |
|
1654 } else { /* add another fd to an already split stream */ |
|
1655 if(!(mfds[fd1]->ct % MULTIOUNIT)) { |
|
1656 int new = sizeof(struct multio) + sizeof(int) * mfds[fd1]->ct; |
|
1657 int old = new - sizeof(int) * MULTIOUNIT; |
|
1658 mfds[fd1] = hrealloc((char *)mfds[fd1], old, new); |
|
1659 } |
|
1660 mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2); |
|
1661 } |
|
1662 } |
|
1663 if (subsh_close >= 0 && !fdtable[subsh_close]) |
|
1664 subsh_close = -1; |
|
1665 } |
|
1666 |
|
1667 /**/ |
|
1668 static void |
|
1669 addvars(Estate state, Wordcode pc, int export) |
|
1670 { |
|
1671 LinkList vl; |
|
1672 int xtr, isstr, htok = 0; |
|
1673 char **arr, **ptr, *name; |
|
1674 Wordcode opc = state->pc; |
|
1675 wordcode ac; |
|
1676 local_list1(svl); |
|
1677 |
|
1678 xtr = isset(XTRACE); |
|
1679 if (xtr) { |
|
1680 printprompt4(); |
|
1681 doneps4 = 1; |
|
1682 } |
|
1683 state->pc = pc; |
|
1684 while (wc_code(ac = *state->pc++) == WC_ASSIGN) { |
|
1685 name = ecgetstr(state, EC_DUPTOK, &htok); |
|
1686 if (htok) |
|
1687 untokenize(name); |
|
1688 if (xtr) |
|
1689 fprintf(xtrerr, |
|
1690 WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC ? "%s+=" : "%s=", name); |
|
1691 if ((isstr = (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR))) { |
|
1692 init_list1(svl, ecgetstr(state, EC_DUPTOK, &htok)); |
|
1693 vl = &svl; |
|
1694 } else |
|
1695 vl = ecgetlist(state, WC_ASSIGN_NUM(ac), EC_DUPTOK, &htok); |
|
1696 |
|
1697 if (vl && htok) { |
|
1698 prefork(vl, (isstr ? (PF_SINGLE|PF_ASSIGN) : |
|
1699 PF_ASSIGN)); |
|
1700 if (errflag) { |
|
1701 state->pc = opc; |
|
1702 return; |
|
1703 } |
|
1704 if (isset(GLOBASSIGN) || !isstr) |
|
1705 globlist(vl, 0); |
|
1706 if (errflag) { |
|
1707 state->pc = opc; |
|
1708 return; |
|
1709 } |
|
1710 } |
|
1711 if (isstr && (empty(vl) || !nextnode(firstnode(vl)))) { |
|
1712 Param pm; |
|
1713 char *val; |
|
1714 int allexp; |
|
1715 |
|
1716 if (empty(vl)) |
|
1717 val = ztrdup(""); |
|
1718 else { |
|
1719 untokenize(peekfirst(vl)); |
|
1720 val = ztrdup(ugetnode(vl)); |
|
1721 } |
|
1722 if (xtr) { |
|
1723 quotedzputs(val, xtrerr); |
|
1724 fputc(' ', xtrerr); |
|
1725 } |
|
1726 if (export && !strchr(name, '[')) { |
|
1727 if (export < 0 && isset(RESTRICTED) && |
|
1728 (pm = (Param) paramtab->removenode(paramtab, name)) && |
|
1729 (pm->flags & PM_RESTRICTED)) { |
|
1730 zerr("%s: restricted", pm->nam, 0); |
|
1731 zsfree(val); |
|
1732 state->pc = opc; |
|
1733 return; |
|
1734 } |
|
1735 if (strcmp(name, "STTY") == 0) { |
|
1736 zsfree(STTYval); |
|
1737 STTYval = ztrdup(val); |
|
1738 } |
|
1739 allexp = opts[ALLEXPORT]; |
|
1740 opts[ALLEXPORT] = 1; |
|
1741 pm = assignsparam(name, val, |
|
1742 WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC); |
|
1743 opts[ALLEXPORT] = allexp; |
|
1744 } else |
|
1745 pm = assignsparam(name, val, |
|
1746 WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC); |
|
1747 if (errflag) { |
|
1748 state->pc = opc; |
|
1749 return; |
|
1750 } |
|
1751 continue; |
|
1752 } |
|
1753 if (vl) { |
|
1754 ptr = arr = (char **) zalloc(sizeof(char **) * |
|
1755 (countlinknodes(vl) + 1)); |
|
1756 |
|
1757 while (nonempty(vl)) |
|
1758 *ptr++ = ztrdup((char *) ugetnode(vl)); |
|
1759 } else |
|
1760 ptr = arr = (char **) zalloc(sizeof(char **)); |
|
1761 |
|
1762 *ptr = NULL; |
|
1763 if (xtr) { |
|
1764 fprintf(xtrerr, "( "); |
|
1765 for (ptr = arr; *ptr; ptr++) { |
|
1766 quotedzputs(*ptr, xtrerr); |
|
1767 fputc(' ', xtrerr); |
|
1768 } |
|
1769 fprintf(xtrerr, ") "); |
|
1770 } |
|
1771 assignaparam(name, arr, WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC); |
|
1772 if (errflag) { |
|
1773 state->pc = opc; |
|
1774 return; |
|
1775 } |
|
1776 } |
|
1777 state->pc = opc; |
|
1778 } |
|
1779 |
|
1780 /**/ |
|
1781 void |
|
1782 setunderscore(char *str) |
|
1783 { |
|
1784 if (str && *str) { |
|
1785 int l = strlen(str) + 1, nl = (l + 31) & ~31; |
|
1786 |
|
1787 if (nl > underscorelen || (underscorelen - nl) > 64) { |
|
1788 zfree(underscore, underscorelen); |
|
1789 underscore = (char *) zalloc(underscorelen = nl); |
|
1790 } |
|
1791 strcpy(underscore, str); |
|
1792 underscoreused = l; |
|
1793 } else { |
|
1794 if (underscorelen > 128) { |
|
1795 zfree(underscore, underscorelen); |
|
1796 underscore = (char *) zalloc(underscorelen = 32); |
|
1797 } |
|
1798 *underscore = '\0'; |
|
1799 underscoreused = 1; |
|
1800 } |
|
1801 } |
|
1802 |
|
1803 /* These describe the type of expansions that need to be done on the words |
|
1804 * used in the thing we are about to execute. They are set in execcmd() and |
|
1805 * used in execsubst() which might be called from one of the functions |
|
1806 * called from execcmd() (like execfor() and so on). */ |
|
1807 |
|
1808 static int esprefork, esglob = 1; |
|
1809 |
|
1810 /**/ |
|
1811 void |
|
1812 execsubst(LinkList strs) |
|
1813 { |
|
1814 if (strs) { |
|
1815 prefork(strs, esprefork); |
|
1816 if (esglob) { |
|
1817 LinkList ostrs = strs; |
|
1818 globlist(strs, 0); |
|
1819 strs = ostrs; |
|
1820 } |
|
1821 } |
|
1822 } |
|
1823 #ifdef __SYMBIAN32__ |
|
1824 extern int handlePipeCmds(char*, pid_t, int fds[3], int); |
|
1825 extern void clearfds(void); |
|
1826 #endif |
|
1827 |
|
1828 /**/ |
|
1829 static void |
|
1830 execcmd(Estate state, int input, int output, int how, int last1) |
|
1831 { |
|
1832 HashNode hn = NULL; |
|
1833 LinkNode node; |
|
1834 Redir fn; |
|
1835 struct multio *mfds[10]; |
|
1836 char *text; |
|
1837 int save[10]; |
|
1838 int fil, dfil, is_cursh, type, do_exec = 0, i, htok = 0; |
|
1839 int nullexec = 0, assign = 0, forked = 0; |
|
1840 int is_shfunc = 0, is_builtin = 0, is_exec = 0, use_defpath = 0; |
|
1841 /* Various flags to the command. */ |
|
1842 int cflags = 0, checked = 0, oautocont = opts[AUTOCONTINUE]; |
|
1843 LinkList redir; |
|
1844 wordcode code; |
|
1845 Wordcode beg = state->pc, varspc; |
|
1846 FILE *oxtrerr = xtrerr; |
|
1847 static int op_fd=-1; |
|
1848 int thread_created=0; |
|
1849 |
|
1850 doneps4 = 0; |
|
1851 redir = (wc_code(*state->pc) == WC_REDIR ? ecgetredirs(state) : NULL); |
|
1852 if (wc_code(*state->pc) == WC_ASSIGN) { |
|
1853 varspc = state->pc; |
|
1854 while (wc_code((code = *state->pc)) == WC_ASSIGN) |
|
1855 state->pc += (WC_ASSIGN_TYPE(code) == WC_ASSIGN_SCALAR ? |
|
1856 3 : WC_ASSIGN_NUM(code) + 2); |
|
1857 } else |
|
1858 varspc = NULL; |
|
1859 |
|
1860 code = *state->pc++; |
|
1861 |
|
1862 type = wc_code(code); |
|
1863 |
|
1864 /* It would be nice if we could use EC_DUPTOK instead of EC_DUP here. |
|
1865 * But for that we would need to check/change all builtins so that |
|
1866 * they don't modify their argument strings. */ |
|
1867 args = (type == WC_SIMPLE ? |
|
1868 ecgetlist(state, WC_SIMPLE_ARGC(code), EC_DUP, &htok) : NULL); |
|
1869 |
|
1870 for (i = 0; i < 10; i++) { |
|
1871 save[i] = -2; |
|
1872 mfds[i] = NULL; |
|
1873 } |
|
1874 |
|
1875 /* If the command begins with `%', then assume it is a * |
|
1876 * reference to a job in the job table. */ |
|
1877 if (type == WC_SIMPLE && args && nonempty(args) && |
|
1878 *(char *)peekfirst(args) == '%') { |
|
1879 if (how & Z_DISOWN) |
|
1880 opts[AUTOCONTINUE] = 1; |
|
1881 pushnode(args, dupstring((how & Z_DISOWN) |
|
1882 ? "disown" : (how & Z_ASYNC) ? "bg" : "fg")); |
|
1883 how = Z_SYNC; |
|
1884 } |
|
1885 |
|
1886 /* If AUTORESUME is set, the command is SIMPLE, and doesn't have * |
|
1887 * any redirections, then check if it matches as a prefix of a * |
|
1888 * job currently in the job table. If it does, then we treat it * |
|
1889 * as a command to resume this job. */ |
|
1890 if (isset(AUTORESUME) && type == WC_SIMPLE && (how & Z_SYNC) && |
|
1891 args && nonempty(args) && (!redir || empty(redir)) && !input && |
|
1892 !nextnode(firstnode(args))) { |
|
1893 if (unset(NOTIFY)) |
|
1894 scanjobs(); |
|
1895 if (findjobnam(peekfirst(args)) != -1) |
|
1896 pushnode(args, dupstring("fg")); |
|
1897 } |
|
1898 |
|
1899 /* Check if it's a builtin needing automatic MAGIC_EQUALS_SUBST * |
|
1900 * handling. Things like typeset need this. We can't detect the * |
|
1901 * command if it contains some tokens (e.g. x=ex; ${x}port), so this * |
|
1902 * only works in simple cases. has_token() is called to make sure * |
|
1903 * this really is a simple case. */ |
|
1904 if (type == WC_SIMPLE) { |
|
1905 while (args && nonempty(args)) { |
|
1906 char* cmdarg= (char *) peekfirst(args); |
|
1907 checked = !has_token(cmdarg); |
|
1908 if (!checked) |
|
1909 break; |
|
1910 if (!(cflags & (BINF_BUILTIN | BINF_COMMAND)) && |
|
1911 (hn = shfunctab->getnode(shfunctab, cmdarg))) { |
|
1912 is_shfunc = 1; |
|
1913 break; |
|
1914 } |
|
1915 if (!(hn = builtintab->getnode(builtintab, cmdarg))) { |
|
1916 checked = !(cflags & BINF_BUILTIN); |
|
1917 break; |
|
1918 } |
|
1919 if (!(hn->flags & BINF_PREFIX)) { |
|
1920 is_builtin = 1; |
|
1921 |
|
1922 /* autoload the builtin if necessary */ |
|
1923 if (!((Builtin) hn)->handlerfunc) { |
|
1924 load_module(((Builtin) hn)->optstr); |
|
1925 hn = builtintab->getnode(builtintab, cmdarg); |
|
1926 } |
|
1927 assign = (hn && (hn->flags & BINF_MAGICEQUALS)); |
|
1928 break; |
|
1929 } |
|
1930 cflags &= ~BINF_BUILTIN & ~BINF_COMMAND; |
|
1931 cflags |= hn->flags; |
|
1932 checked = 0; |
|
1933 if (cflags & BINF_COMMAND && nextnode(firstnode(args))) { |
|
1934 /* check for options to command builtin */ |
|
1935 char *next = (char *) getdata(nextnode(firstnode(args))); |
|
1936 char *cmdopt; |
|
1937 if (next && *next == '-' && strlen(next) == 2 && |
|
1938 (cmdopt = strchr("pvV", next[1]))) |
|
1939 { |
|
1940 if (*cmdopt == 'p') { |
|
1941 uremnode(args, firstnode(args)); |
|
1942 use_defpath = 1; |
|
1943 if (nextnode(firstnode(args))) |
|
1944 next = (char *) getdata(nextnode(firstnode(args))); |
|
1945 } else { |
|
1946 hn = (HashNode)&commandbn; |
|
1947 is_builtin = 1; |
|
1948 break; |
|
1949 } |
|
1950 } |
|
1951 if (!strcmp(next, "--")) |
|
1952 uremnode(args, firstnode(args)); |
|
1953 } |
|
1954 uremnode(args, firstnode(args)); |
|
1955 hn = NULL; |
|
1956 if ((cflags & BINF_COMMAND) && unset(POSIXBUILTINS)) |
|
1957 break; |
|
1958 } |
|
1959 } |
|
1960 |
|
1961 /* Do prefork substitutions */ |
|
1962 esprefork = (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0; |
|
1963 if (args && htok) |
|
1964 prefork(args, esprefork); |
|
1965 |
|
1966 if (type == WC_SIMPLE) { |
|
1967 int unglobbed = 0; |
|
1968 |
|
1969 for (;;) { |
|
1970 char *cmdarg; |
|
1971 |
|
1972 if (!(cflags & BINF_NOGLOB)) |
|
1973 while (!checked && !errflag && args && nonempty(args) && |
|
1974 has_token((char *) peekfirst(args))) |
|
1975 zglob(args, firstnode(args), 0); |
|
1976 else if (!unglobbed) { |
|
1977 for (node = firstnode(args); node; incnode(node)) |
|
1978 untokenize((char *) getdata(node)); |
|
1979 unglobbed = 1; |
|
1980 } |
|
1981 |
|
1982 /* Current shell should not fork unless the * |
|
1983 * exec occurs at the end of a pipeline. */ |
|
1984 if ((cflags & BINF_EXEC) && last1) |
|
1985 do_exec = 1; |
|
1986 |
|
1987 /* Empty command */ |
|
1988 if (!args || empty(args)) { |
|
1989 if (redir && nonempty(redir)) { |
|
1990 if (do_exec) { |
|
1991 /* Was this "exec < foobar"? */ |
|
1992 nullexec = 1; |
|
1993 break; |
|
1994 } else if (varspc) { |
|
1995 nullexec = 2; |
|
1996 break; |
|
1997 } else if (!nullcmd || !*nullcmd || opts[CSHNULLCMD] || |
|
1998 (cflags & BINF_PREFIX)) { |
|
1999 zerr("redirection with no command", NULL, 0); |
|
2000 errflag = lastval = 1; |
|
2001 return; |
|
2002 } else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) { |
|
2003 if (!args) |
|
2004 args = newlinklist(); |
|
2005 addlinknode(args, dupstring(":")); |
|
2006 } else if (readnullcmd && *readnullcmd && |
|
2007 ((Redir) peekfirst(redir))->type == REDIR_READ && |
|
2008 !nextnode(firstnode(redir))) { |
|
2009 if (!args) |
|
2010 args = newlinklist(); |
|
2011 addlinknode(args, dupstring(readnullcmd)); |
|
2012 } else { |
|
2013 if (!args) |
|
2014 args = newlinklist(); |
|
2015 addlinknode(args, dupstring(nullcmd)); |
|
2016 } |
|
2017 } else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) { |
|
2018 lastval = 0; |
|
2019 return; |
|
2020 } else { |
|
2021 cmdoutval = 0; |
|
2022 if (varspc) |
|
2023 addvars(state, varspc, 0); |
|
2024 if (errflag) |
|
2025 lastval = errflag; |
|
2026 else |
|
2027 lastval = cmdoutval; |
|
2028 if (isset(XTRACE)) { |
|
2029 fputc('\n', xtrerr); |
|
2030 fflush(xtrerr); |
|
2031 } |
|
2032 return; |
|
2033 } |
|
2034 } else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && do_exec) { |
|
2035 zerrnam("exec", "%s: restricted", |
|
2036 (char *) getdata(firstnode(args)), 0); |
|
2037 lastval = 1; |
|
2038 return; |
|
2039 } |
|
2040 |
|
2041 /* |
|
2042 * Quit looking for a command if: |
|
2043 * - there was an error; or |
|
2044 * - we checked the simple cases needing MAGIC_EQUAL_SUBST; or |
|
2045 * - we know we already found a builtin (because either: |
|
2046 * - we loaded a builtin from a module, or |
|
2047 * - we have determined there are options which would |
|
2048 * require us to use the "command" builtin); or |
|
2049 * - we aren't using POSIX and so BINF_COMMAND indicates a zsh |
|
2050 * precommand modifier is being used in place of the builtin |
|
2051 */ |
|
2052 if (errflag || checked || is_builtin || |
|
2053 (unset(POSIXBUILTINS) && (cflags & BINF_COMMAND))) |
|
2054 break; |
|
2055 |
|
2056 cmdarg = (char *) peekfirst(args); |
|
2057 if (!(cflags & (BINF_BUILTIN | BINF_COMMAND)) && |
|
2058 (hn = shfunctab->getnode(shfunctab, cmdarg))) { |
|
2059 is_shfunc = 1; |
|
2060 break; |
|
2061 } |
|
2062 if (!(hn = builtintab->getnode(builtintab, cmdarg))) { |
|
2063 if (cflags & BINF_BUILTIN) { |
|
2064 zwarn("no such builtin: %s", cmdarg, 0); |
|
2065 lastval = 1; |
|
2066 opts[AUTOCONTINUE] = oautocont; |
|
2067 return; |
|
2068 } |
|
2069 break; |
|
2070 } |
|
2071 if (!(hn->flags & BINF_PREFIX)) { |
|
2072 is_builtin = 1; |
|
2073 |
|
2074 /* autoload the builtin if necessary */ |
|
2075 if (!((Builtin) hn)->handlerfunc) { |
|
2076 load_module(((Builtin) hn)->optstr); |
|
2077 hn = builtintab->getnode(builtintab, cmdarg); |
|
2078 } |
|
2079 break; |
|
2080 } |
|
2081 cflags &= ~BINF_BUILTIN & ~BINF_COMMAND; |
|
2082 cflags |= hn->flags; |
|
2083 uremnode(args, firstnode(args)); |
|
2084 hn = NULL; |
|
2085 } |
|
2086 } |
|
2087 |
|
2088 if (errflag) { |
|
2089 lastval = 1; |
|
2090 opts[AUTOCONTINUE] = oautocont; |
|
2091 return; |
|
2092 } |
|
2093 |
|
2094 /* Get the text associated with this command. */ |
|
2095 if ((how & Z_ASYNC) || |
|
2096 (!sfcontext && !sourcelevel && (jobbing || (how & Z_TIMED)))) |
|
2097 text = getjobtext(state->prog, beg); |
|
2098 else |
|
2099 text = NULL; |
|
2100 |
|
2101 /* Set up special parameter $_ */ |
|
2102 |
|
2103 setunderscore((args && nonempty(args)) ? ((char *) getdata(lastnode(args))) : ""); |
|
2104 |
|
2105 /* Warn about "rm *" */ |
|
2106 if (type == WC_SIMPLE && interact && unset(RMSTARSILENT) && |
|
2107 isset(SHINSTDIN) && args && nonempty(args) && |
|
2108 nextnode(firstnode(args)) && !strcmp(peekfirst(args), "rm")) { |
|
2109 LinkNode node, next; |
|
2110 |
|
2111 for (node = nextnode(firstnode(args)); node && !errflag; node = next) { |
|
2112 char *s = (char *) getdata(node); |
|
2113 int l = strlen(s); |
|
2114 |
|
2115 next = nextnode(node); |
|
2116 if (s[0] == Star && !s[1]) { |
|
2117 if (!checkrmall(pwd)) |
|
2118 uremnode(args, node); |
|
2119 } else if (l > 2 && s[l - 2] == '/' && s[l - 1] == Star) { |
|
2120 char t = s[l - 2]; |
|
2121 |
|
2122 s[l - 2] = 0; |
|
2123 if (!checkrmall(s)) |
|
2124 uremnode(args, node); |
|
2125 s[l - 2] = t; |
|
2126 } |
|
2127 } |
|
2128 if (!nextnode(firstnode(args))) |
|
2129 errflag = 1; |
|
2130 } |
|
2131 |
|
2132 if (errflag) { |
|
2133 lastval = 1; |
|
2134 opts[AUTOCONTINUE] = oautocont; |
|
2135 return; |
|
2136 } |
|
2137 |
|
2138 if (type == WC_SIMPLE && !nullexec) { |
|
2139 char *s; |
|
2140 char trycd = (isset(AUTOCD) && isset(SHINSTDIN) && |
|
2141 (!redir || empty(redir)) && args && !empty(args) && |
|
2142 !nextnode(firstnode(args)) && *(char *)peekfirst(args)); |
|
2143 |
|
2144 DPUTS((!args || empty(args)), "BUG: empty(args) in exec.c"); |
|
2145 #ifndef __SYMBIAN32__ |
|
2146 if (!hn) { |
|
2147 /* Resolve external commands */ |
|
2148 char *cmdarg = (char *) peekfirst(args); |
|
2149 char **checkpath = pathchecked; |
|
2150 int dohashcmd = isset(HASHCMDS); |
|
2151 |
|
2152 hn = cmdnamtab->getnode(cmdnamtab, cmdarg); |
|
2153 if (hn && trycd && !isreallycom((Cmdnam)hn)) { |
|
2154 if (!(((Cmdnam)hn)->flags & HASHED)) { |
|
2155 checkpath = path; |
|
2156 dohashcmd = 1; |
|
2157 } |
|
2158 cmdnamtab->removenode(cmdnamtab, cmdarg); |
|
2159 cmdnamtab->freenode(hn); |
|
2160 hn = NULL; |
|
2161 } |
|
2162 if (!hn && dohashcmd && strcmp(cmdarg, "..")) { |
|
2163 for (s = cmdarg; *s && *s != '/'; s++); |
|
2164 if (!*s) |
|
2165 hn = (HashNode) hashcmd(cmdarg, checkpath); |
|
2166 } |
|
2167 } |
|
2168 #endif //__SYMBIAN32__ |
|
2169 /* If no command found yet, see if it * |
|
2170 * is a directory we should AUTOCD to. */ |
|
2171 if (!hn && trycd && (s = cancd(peekfirst(args)))) { |
|
2172 peekfirst(args) = (void *) s; |
|
2173 pushnode(args, dupstring("cd")); |
|
2174 if ((hn = builtintab->getnode(builtintab, "cd"))) |
|
2175 is_builtin = 1; |
|
2176 } |
|
2177 } |
|
2178 |
|
2179 /* This is nonzero if the command is a current shell procedure? */ |
|
2180 is_cursh = (is_builtin || is_shfunc || nullexec || type >= WC_CURSH); |
|
2181 |
|
2182 /************************************************************************** |
|
2183 * Do we need to fork? We need to fork if: * |
|
2184 * 1) The command is supposed to run in the background. (or) * |
|
2185 * 2) There is no `exec' flag, and either: * |
|
2186 * a) This is a builtin or shell function with output piped somewhere. * |
|
2187 * b) This is an external command and we can't do a `fake exec'. * |
|
2188 * * |
|
2189 * A `fake exec' is possible if we have all the following conditions: * |
|
2190 * 1) last1 flag is 1. This indicates that the current shell will not * |
|
2191 * be needed after the current command. This is typically the case * |
|
2192 * when when the command is the last stage in a subshell, or is the * |
|
2193 * last command after the option `-c'. * |
|
2194 * 2) We don't have any traps set. * |
|
2195 * 3) We don't have any files to delete. * |
|
2196 * * |
|
2197 * The condition above for a `fake exec' will also work for a current * |
|
2198 * shell command such as a builtin, but doesn't really buy us anything * |
|
2199 * (doesn't save us a process), since it is already running in the * |
|
2200 * current shell. * |
|
2201 **************************************************************************/ |
|
2202 |
|
2203 if ((how & Z_ASYNC) || |
|
2204 (!do_exec && |
|
2205 (((is_builtin || is_shfunc) && output) || |
|
2206 (!is_cursh && (last1 != 1 || nsigtrapped || havefiles()))))) { |
|
2207 |
|
2208 // forked = 1; |
|
2209 |
|
2210 |
|
2211 if (sigtrapped[SIGINT] & ZSIG_IGNORED) |
|
2212 holdintr(); |
|
2213 #ifdef HAVE_NICE |
|
2214 /* Check if we should run background jobs at a lower priority. */ |
|
2215 if ((how & Z_ASYNC) && isset(BGNICE)) |
|
2216 nice(5); |
|
2217 #endif /* HAVE_NICE */ |
|
2218 |
|
2219 } else if (is_cursh) { |
|
2220 /* This is a current shell procedure that didn't need to fork. * |
|
2221 * This includes current shell procedures that are being exec'ed, * |
|
2222 * as well as null execs. */ |
|
2223 jobtab[thisjob].stat |= STAT_CURSH; |
|
2224 } else { |
|
2225 /* This is an exec (real or fake) for an external command. * |
|
2226 * Note that any form of exec means that the subshell is fake * |
|
2227 * (but we may be in a subshell already). */ |
|
2228 is_exec = 1; |
|
2229 } |
|
2230 |
|
2231 |
|
2232 if ((esglob = !(cflags & BINF_NOGLOB)) && args && htok) { |
|
2233 LinkList oargs = args; |
|
2234 globlist(args, 0); |
|
2235 args = oargs; |
|
2236 } |
|
2237 if (errflag) { |
|
2238 lastval = 1; |
|
2239 goto err; |
|
2240 } |
|
2241 |
|
2242 /* Make a copy of stderr for xtrace output before redirecting */ |
|
2243 fflush(xtrerr); |
|
2244 if (isset(XTRACE) && xtrerr == stderr && |
|
2245 (type < WC_SUBSH || type == WC_TIMED)) { |
|
2246 if (!(xtrerr = fdopen(movefd(dup(fileno(stderr))), "w"))) |
|
2247 xtrerr = stderr; |
|
2248 else |
|
2249 fdtable[fileno(xtrerr)] = 3; |
|
2250 } |
|
2251 |
|
2252 /* Add pipeline input/output to mnodes */ |
|
2253 #ifndef __SYMBIAN32__ |
|
2254 if (input) |
|
2255 { |
|
2256 addfd(forked, save, mfds, 0, input, 0); |
|
2257 } |
|
2258 |
|
2259 if (output) |
|
2260 { |
|
2261 addfd(forked, save, mfds, 1, output, 1); |
|
2262 } |
|
2263 #endif |
|
2264 /* Do process substitutions */ |
|
2265 if (redir) |
|
2266 spawnpipes(redir, nullexec); |
|
2267 |
|
2268 /* Do io redirections */ |
|
2269 while (redir && nonempty(redir)) { |
|
2270 fn = (Redir) ugetnode(redir); |
|
2271 DPUTS(fn->type == REDIR_HEREDOC || fn->type == REDIR_HEREDOCDASH, |
|
2272 "BUG: unexpanded here document"); |
|
2273 if (fn->type == REDIR_INPIPE) { |
|
2274 if (fn->fd2 == -1) { |
|
2275 closemnodes(mfds); |
|
2276 fixfds(save); |
|
2277 execerr(); |
|
2278 } |
|
2279 addfd(forked, save, mfds, fn->fd1, fn->fd2, 0); |
|
2280 } else if (fn->type == REDIR_OUTPIPE) { |
|
2281 if (fn->fd2 == -1) { |
|
2282 closemnodes(mfds); |
|
2283 fixfds(save); |
|
2284 execerr(); |
|
2285 } |
|
2286 addfd(forked, save, mfds, fn->fd1, fn->fd2, 1); |
|
2287 } else { |
|
2288 if (fn->type != REDIR_HERESTR && xpandredir(fn, redir)) |
|
2289 continue; |
|
2290 if (errflag) { |
|
2291 closemnodes(mfds); |
|
2292 fixfds(save); |
|
2293 execerr(); |
|
2294 } |
|
2295 if (isset(RESTRICTED) && IS_WRITE_FILE(fn->type)) { |
|
2296 zwarn("writing redirection not allowed in restricted mode", NULL, 0); |
|
2297 execerr(); |
|
2298 } |
|
2299 if (unset(EXECOPT)) |
|
2300 continue; |
|
2301 switch(fn->type) { |
|
2302 case REDIR_HERESTR: |
|
2303 fil = getherestr(fn); |
|
2304 if (fil == -1) { |
|
2305 closemnodes(mfds); |
|
2306 fixfds(save); |
|
2307 if (errno != EINTR) |
|
2308 zwarn("%e", NULL, errno); |
|
2309 execerr(); |
|
2310 } |
|
2311 addfd(forked, save, mfds, fn->fd1, fil, 0); |
|
2312 break; |
|
2313 case REDIR_READ: |
|
2314 case REDIR_READWRITE: |
|
2315 if (fn->type == REDIR_READ) |
|
2316 fil = open(unmeta(fn->name), O_RDONLY | O_NOCTTY); |
|
2317 else |
|
2318 fil = open(unmeta(fn->name), |
|
2319 O_RDWR | O_CREAT | O_NOCTTY, 0666); |
|
2320 if (fil == -1) { |
|
2321 closemnodes(mfds); |
|
2322 fixfds(save); |
|
2323 if (errno != EINTR) |
|
2324 zwarn("%e: %s", fn->name, errno); |
|
2325 execerr(); |
|
2326 } |
|
2327 addfd(forked, save, mfds, fn->fd1, fil, 0); |
|
2328 /* If this is 'exec < file', read from stdin, * |
|
2329 * not terminal, unless `file' is a terminal. */ |
|
2330 if (nullexec == 1 && fn->fd1 == 0 && |
|
2331 isset(SHINSTDIN) && interact && !zleactive) |
|
2332 init_io(); |
|
2333 break; |
|
2334 case REDIR_CLOSE: |
|
2335 if (!forked && fn->fd1 < 10 && save[fn->fd1] == -2) |
|
2336 save[fn->fd1] = movefd(fn->fd1); |
|
2337 closemn(mfds, fn->fd1); |
|
2338 zclose(fn->fd1); |
|
2339 break; |
|
2340 case REDIR_MERGEIN: |
|
2341 case REDIR_MERGEOUT: |
|
2342 if (fn->fd2 < 10) |
|
2343 closemn(mfds, fn->fd2); |
|
2344 if (fn->fd2 > 9 && |
|
2345 (fdtable[fn->fd2] || |
|
2346 fn->fd2 == coprocin || |
|
2347 fn->fd2 == coprocout)) { |
|
2348 fil = -1; |
|
2349 errno = EBADF; |
|
2350 } else { |
|
2351 int fd = fn->fd2; |
|
2352 if(fd == -2) |
|
2353 fd = (fn->type == REDIR_MERGEOUT) ? coprocout : coprocin; |
|
2354 fil = dup(fd); |
|
2355 } |
|
2356 if (fil == -1) { |
|
2357 char fdstr[4]; |
|
2358 |
|
2359 closemnodes(mfds); |
|
2360 fixfds(save); |
|
2361 if (fn->fd2 != -2) |
|
2362 sprintf(fdstr, "%d", fn->fd2); |
|
2363 zwarn("%s: %e", fn->fd2 == -2 ? "coprocess" : fdstr, errno); |
|
2364 execerr(); |
|
2365 } |
|
2366 addfd(forked, save, mfds, fn->fd1, fil, fn->type == REDIR_MERGEOUT); |
|
2367 break; |
|
2368 default: |
|
2369 if (IS_APPEND_REDIR(fn->type)) |
|
2370 fil = open(unmeta(fn->name), |
|
2371 (unset(CLOBBER) && !IS_CLOBBER_REDIR(fn->type)) ? |
|
2372 O_WRONLY | O_APPEND | O_NOCTTY : |
|
2373 O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, 0666); |
|
2374 else |
|
2375 fil = clobber_open(fn); |
|
2376 if(fil != -1 && IS_ERROR_REDIR(fn->type)) |
|
2377 dfil = dup(fil); |
|
2378 else |
|
2379 dfil = 0; |
|
2380 if (fil == -1 || dfil == -1) { |
|
2381 if(fil != -1) |
|
2382 close(fil); |
|
2383 closemnodes(mfds); |
|
2384 fixfds(save); |
|
2385 if (errno != EINTR) |
|
2386 zwarn("%e: %s", fn->name, errno); |
|
2387 execerr(); |
|
2388 } |
|
2389 addfd(forked, save, mfds, fn->fd1, fil, 1); |
|
2390 if(IS_ERROR_REDIR(fn->type)) |
|
2391 addfd(forked, save, mfds, 2, dfil, 1); |
|
2392 break; |
|
2393 } |
|
2394 } |
|
2395 } |
|
2396 |
|
2397 /* We are done with redirection. close the mnodes, * |
|
2398 * spawning tee/cat processes as necessary. */ |
|
2399 for (i = 0; i < 10; i++) |
|
2400 if (mfds[i] && mfds[i]->ct >= 2) |
|
2401 closemn(mfds, i); |
|
2402 |
|
2403 if (nullexec) { |
|
2404 if (nullexec == 1) { |
|
2405 /* |
|
2406 * If nullexec is 1 we specifically *don't* restore the original |
|
2407 * fd's before returning. |
|
2408 */ |
|
2409 for (i = 0; i < 10; i++) |
|
2410 if (save[i] != -2) |
|
2411 zclose(save[i]); |
|
2412 goto done; |
|
2413 } |
|
2414 /* |
|
2415 * If nullexec is 2, we have variables to add with the redirections |
|
2416 * in place. |
|
2417 */ |
|
2418 if (varspc) |
|
2419 addvars(state, varspc, 0); |
|
2420 lastval = errflag ? errflag : cmdoutval; |
|
2421 if (isset(XTRACE)) { |
|
2422 fputc('\n', xtrerr); |
|
2423 fflush(xtrerr); |
|
2424 } |
|
2425 } else if (isset(EXECOPT) && !errflag) { |
|
2426 /* |
|
2427 * We delay the entersubsh() to here when we are exec'ing |
|
2428 * the current shell (including a fake exec to run a builtin then |
|
2429 * exit) in case there is an error return. |
|
2430 */ |
|
2431 if (is_exec) |
|
2432 entersubsh(how, (type != WC_SUBSH) ? 2 : 1, 1, |
|
2433 (do_exec || (type >= WC_CURSH && last1 == 1)) |
|
2434 && !forked); |
|
2435 if (type >= WC_CURSH) { |
|
2436 if (last1 == 1) |
|
2437 do_exec = 1; |
|
2438 lastval = (execfuncs[type - WC_CURSH])(state, do_exec); |
|
2439 } else if (is_builtin || is_shfunc) { |
|
2440 LinkList restorelist = 0, removelist = 0; |
|
2441 /* builtin or shell function */ |
|
2442 |
|
2443 if (!forked && ((cflags & BINF_COMMAND) || |
|
2444 (unset(POSIXBUILTINS) && !assign) || |
|
2445 (isset(POSIXBUILTINS) && !is_shfunc && |
|
2446 !(hn->flags & BINF_PSPECIAL)))) { |
|
2447 if (varspc) |
|
2448 save_params(state, varspc, &restorelist, &removelist); |
|
2449 else |
|
2450 restorelist = removelist = NULL; |
|
2451 } |
|
2452 if (varspc) { |
|
2453 /* Export this if the command is a shell function, |
|
2454 * but not if it's a builtin. |
|
2455 */ |
|
2456 addvars(state, varspc, is_shfunc); |
|
2457 if (errflag) { |
|
2458 if (restorelist) |
|
2459 restore_params(restorelist, removelist); |
|
2460 lastval = 1; |
|
2461 fixfds(save); |
|
2462 goto done; |
|
2463 } |
|
2464 } |
|
2465 |
|
2466 if (is_shfunc) { |
|
2467 /* It's a shell function */ |
|
2468 |
|
2469 #ifdef PATH_DEV_FD |
|
2470 int i; |
|
2471 |
|
2472 for (i = 10; i <= max_zsh_fd; i++) |
|
2473 if (fdtable[i] > 1) |
|
2474 fdtable[i]++; |
|
2475 #endif |
|
2476 if (subsh_close >= 0) |
|
2477 zclose(subsh_close); |
|
2478 subsh_close = -1; |
|
2479 |
|
2480 execshfunc((Shfunc) hn, args); |
|
2481 #ifdef PATH_DEV_FD |
|
2482 for (i = 10; i <= max_zsh_fd; i++) |
|
2483 if (fdtable[i] > 1) |
|
2484 if (--(fdtable[i]) <= 2) |
|
2485 zclose(i); |
|
2486 #endif |
|
2487 } else { |
|
2488 /* It's a builtin */ |
|
2489 if (forked) |
|
2490 closem(1); |
|
2491 |
|
2492 lastval = execbuiltin(args, (Builtin) hn, input, output); |
|
2493 |
|
2494 #ifdef PATH_DEV_FD |
|
2495 closem(2); |
|
2496 #endif |
|
2497 fflush(stdout); |
|
2498 #ifdef __SYMBIAN32__ |
|
2499 fflush(stderr); |
|
2500 #endif |
|
2501 if (save[1] == -2) { |
|
2502 if (ferror(stdout)) { |
|
2503 zwarn("write error: %e", NULL, errno); |
|
2504 clearerr(stdout); |
|
2505 } |
|
2506 } else |
|
2507 clearerr(stdout); |
|
2508 } |
|
2509 if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) && |
|
2510 lastval && !subsh) { |
|
2511 fprintf(stderr, "zsh: exit %ld\n", (long)lastval); |
|
2512 } |
|
2513 |
|
2514 if (do_exec) { |
|
2515 if (subsh) |
|
2516 _exit(lastval); |
|
2517 |
|
2518 /* If we are exec'ing a command, and we are not in a subshell, * |
|
2519 * then check if we should save the history file. */ |
|
2520 if (isset(RCS) && interact && !nohistsave) |
|
2521 savehistfile(NULL, 1, HFILE_USE_OPTIONS); |
|
2522 exit(lastval); |
|
2523 } |
|
2524 if (restorelist) |
|
2525 restore_params(restorelist, removelist); |
|
2526 |
|
2527 } else { |
|
2528 pid_t pid; |
|
2529 int fds[3]; |
|
2530 struct timeval bgtime; |
|
2531 struct timezone dummy_tz; |
|
2532 char* arg0 = (char *) peekfirst(args); |
|
2533 |
|
2534 gettimeofday(&bgtime, &dummy_tz); |
|
2535 |
|
2536 if (!forked) |
|
2537 setiparam("SHLVL", --shlvl); |
|
2538 if (do_exec) { |
|
2539 /* If we are exec'ing a command, and we are not * |
|
2540 * in a subshell, then save the history file. */ |
|
2541 if (!subsh && isset(RCS) && interact && !nohistsave) |
|
2542 savehistfile(NULL, 1, HFILE_USE_OPTIONS); |
|
2543 } |
|
2544 if (varspc) { |
|
2545 addvars(state, varspc, -1); |
|
2546 if (errflag) |
|
2547 _exit(1); |
|
2548 } |
|
2549 closem(1); |
|
2550 if (coprocin) |
|
2551 zclose(coprocin); |
|
2552 if (coprocout) |
|
2553 zclose(coprocout); |
|
2554 #ifdef HAVE_GETRLIMIT |
|
2555 if (!forked) |
|
2556 setlimits(NULL); |
|
2557 #endif |
|
2558 if (how & Z_ASYNC) { |
|
2559 zsfree(STTYval); |
|
2560 STTYval = 0; |
|
2561 } |
|
2562 |
|
2563 #ifdef __SYMBIAN32__ |
|
2564 { |
|
2565 //find and execute the external command |
|
2566 const int data_size=512; |
|
2567 char data[data_size]; |
|
2568 int read_cnt=0; |
|
2569 char** argv; |
|
2570 fd_set readfds; |
|
2571 int status=-1; |
|
2572 size_t oldcmdlen=0, newcmdlen=0; |
|
2573 struct timeval tv; |
|
2574 char *pcmd=NULL; |
|
2575 char* pfile=NULL; |
|
2576 |
|
2577 //generate full path |
|
2578 argv=makecline(args); |
|
2579 pfile=argv[0]; |
|
2580 |
|
2581 //generate commands |
|
2582 while(++argv && *argv) |
|
2583 { |
|
2584 newcmdlen=strlen(*argv)+newcmdlen+1; |
|
2585 if(!pcmd) |
|
2586 pcmd=(char*)calloc(newcmdlen+1, sizeof(char)); |
|
2587 else |
|
2588 pcmd=(char*)realloc(pcmd, newcmdlen+1); |
|
2589 |
|
2590 sprintf(pcmd+oldcmdlen, "%s ", *argv); |
|
2591 oldcmdlen=newcmdlen; |
|
2592 } |
|
2593 |
|
2594 //execute the external command |
|
2595 if ( (pid=popen3(pfile, pcmd, environ, fds)) == -1) |
|
2596 { |
|
2597 zerr("command not found: %s", arg0, 0); |
|
2598 opts[AUTOCONTINUE] = oautocont; |
|
2599 clearfds(); |
|
2600 free(pcmd); |
|
2601 lastval=127; |
|
2602 return; |
|
2603 } |
|
2604 free(pcmd); |
|
2605 |
|
2606 if(input || output) |
|
2607 { |
|
2608 handlePipeCmds(pfile, pid, fds, output); |
|
2609 } |
|
2610 else |
|
2611 { |
|
2612 //read the output from the executed command |
|
2613 for(;;) |
|
2614 { |
|
2615 int wait_pid=waitpid(pid, &status, WNOHANG); |
|
2616 if(pid == wait_pid || wait_pid == -1) //dont wait for the child to terminate |
|
2617 { |
|
2618 int max= MAX(fds[1], fds[2]); |
|
2619 |
|
2620 FD_ZERO(&readfds); |
|
2621 FD_SET(fds[1], &readfds); |
|
2622 FD_SET(fds[2], &readfds); |
|
2623 |
|
2624 //read available data, if child is terminated already. |
|
2625 for(;;) |
|
2626 { |
|
2627 tv.tv_sec = 1; |
|
2628 tv.tv_usec = 0; |
|
2629 |
|
2630 if(select(max+1, &readfds, NULL, NULL, &tv) <=0) |
|
2631 break; |
|
2632 else |
|
2633 { |
|
2634 if(FD_ISSET(fds[1], &readfds)) |
|
2635 { |
|
2636 memset(&data[0], 0, 512); |
|
2637 read_cnt=read(fds[1], &data[0], 512); |
|
2638 if(read_cnt>0) |
|
2639 write(1, data, read_cnt); |
|
2640 } |
|
2641 |
|
2642 if(FD_ISSET(fds[2], &readfds)) |
|
2643 { |
|
2644 memset(&data[0], 0, 512); |
|
2645 read_cnt=read(fds[2], &data[0], 512); |
|
2646 if(read_cnt>0) |
|
2647 write(2, data, read_cnt); |
|
2648 } |
|
2649 } |
|
2650 } |
|
2651 //Updating the Error status. |
|
2652 if(WIFEXITED(status)) |
|
2653 lastval = WEXITSTATUS(status); |
|
2654 else if(WIFTERMINATED(status)) |
|
2655 lastval = WTERMINATESTATUS(status); |
|
2656 else if(WIFPANICED(status)) |
|
2657 lastval = WPANICCODE(status); |
|
2658 break; |
|
2659 } |
|
2660 else |
|
2661 { |
|
2662 int max= MAX(0, MAX(fds[1], fds[2])); |
|
2663 |
|
2664 FD_ZERO(&readfds); |
|
2665 FD_SET(fds[1], &readfds); |
|
2666 FD_SET(fds[2], &readfds); |
|
2667 FD_SET(0, &readfds); |
|
2668 |
|
2669 tv.tv_sec = 1; |
|
2670 tv.tv_usec = 0; |
|
2671 |
|
2672 if(select(max+1, &readfds, NULL, NULL, &tv) < 0) |
|
2673 break; |
|
2674 |
|
2675 else |
|
2676 { |
|
2677 if(FD_ISSET(fds[1], &readfds)) |
|
2678 { |
|
2679 memset(&data[0], 0, 512); |
|
2680 read_cnt=read(fds[1], &data[0], 512); |
|
2681 if(read_cnt>0) |
|
2682 write(1, data, read_cnt); |
|
2683 } |
|
2684 |
|
2685 if(FD_ISSET(fds[2], &readfds)) |
|
2686 { |
|
2687 memset(&data[0], 0, 512); |
|
2688 read_cnt=read(fds[2], &data[0], 512); |
|
2689 if(read_cnt>0) |
|
2690 write(2, data, read_cnt); |
|
2691 } |
|
2692 |
|
2693 if(FD_ISSET(0, &readfds)) |
|
2694 { |
|
2695 memset(&data[0], 0, 512); |
|
2696 read_cnt=read(0, &data[0], 512); |
|
2697 if(read_cnt>0) |
|
2698 write(fds[0], data, read_cnt); |
|
2699 } |
|
2700 }//else |
|
2701 |
|
2702 } //else |
|
2703 }//for (;;) |
|
2704 close(fds[0]); |
|
2705 close(fds[1]); |
|
2706 close(fds[2]); |
|
2707 } |
|
2708 } |
|
2709 #endif |
|
2710 if (how & Z_ASYNC) { |
|
2711 lastpid = (zlong) pid; |
|
2712 } else if (!jobtab[thisjob].stty_in_env && varspc) { |
|
2713 /* search for STTY=... */ |
|
2714 Wordcode p = varspc; |
|
2715 wordcode ac; |
|
2716 |
|
2717 while (wc_code(ac = *p) == WC_ASSIGN) { |
|
2718 if (!strcmp(ecrawstr(state->prog, p + 1, NULL), "STTY")) { |
|
2719 jobtab[thisjob].stty_in_env = 1; |
|
2720 break; |
|
2721 } |
|
2722 p += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ? |
|
2723 3 : WC_ASSIGN_NUM(ac) + 2); |
|
2724 } |
|
2725 } |
|
2726 opts[AUTOCONTINUE] = oautocont; |
|
2727 fixfds(save); |
|
2728 return; |
|
2729 } |
|
2730 } |
|
2731 |
|
2732 err: |
|
2733 if (forked) |
|
2734 _exit(lastval); |
|
2735 fixfds(save); |
|
2736 |
|
2737 done: |
|
2738 if (xtrerr != oxtrerr) { |
|
2739 fil = fileno(xtrerr); |
|
2740 fclose(xtrerr); |
|
2741 xtrerr = oxtrerr; |
|
2742 zclose(fil); |
|
2743 } |
|
2744 |
|
2745 zsfree(STTYval); |
|
2746 STTYval = 0; |
|
2747 opts[AUTOCONTINUE] = oautocont; |
|
2748 |
|
2749 } |
|
2750 |
|
2751 /* Arrange to have variables restored. */ |
|
2752 |
|
2753 /**/ |
|
2754 static void |
|
2755 save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p) |
|
2756 { |
|
2757 Param pm; |
|
2758 char *s; |
|
2759 wordcode ac; |
|
2760 |
|
2761 *restore_p = newlinklist(); |
|
2762 *remove_p = newlinklist(); |
|
2763 |
|
2764 while (wc_code(ac = *pc) == WC_ASSIGN) { |
|
2765 s = ecrawstr(state->prog, pc + 1, NULL); |
|
2766 if ((pm = (Param) paramtab->getnode(paramtab, s))) { |
|
2767 if (pm->env) |
|
2768 delenv(pm); |
|
2769 if (!(pm->flags & PM_SPECIAL)) { |
|
2770 paramtab->removenode(paramtab, s); |
|
2771 } else if (!(pm->flags & PM_READONLY) && |
|
2772 (unset(RESTRICTED) || !(pm->flags & PM_RESTRICTED))) { |
|
2773 Param tpm = (Param) hcalloc(sizeof *tpm); |
|
2774 tpm->nam = pm->nam; |
|
2775 copyparam(tpm, pm, 1); |
|
2776 pm = tpm; |
|
2777 } |
|
2778 addlinknode(*remove_p, dupstring(s)); |
|
2779 addlinknode(*restore_p, pm); |
|
2780 } else |
|
2781 addlinknode(*remove_p, dupstring(s)); |
|
2782 |
|
2783 pc += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ? |
|
2784 3 : WC_ASSIGN_NUM(ac) + 2); |
|
2785 } |
|
2786 } |
|
2787 |
|
2788 /* Restore saved parameters after executing a shfunc or builtin */ |
|
2789 |
|
2790 /**/ |
|
2791 static void |
|
2792 restore_params(LinkList restorelist, LinkList removelist) |
|
2793 { |
|
2794 Param pm; |
|
2795 char *s; |
|
2796 |
|
2797 /* remove temporary parameters */ |
|
2798 while ((s = (char *) ugetnode(removelist))) { |
|
2799 if ((pm = (Param) paramtab->getnode(paramtab, s)) && |
|
2800 !(pm->flags & PM_SPECIAL)) { |
|
2801 pm->flags &= ~PM_READONLY; |
|
2802 unsetparam_pm(pm, 0, 0); |
|
2803 } |
|
2804 } |
|
2805 |
|
2806 if (restorelist) { |
|
2807 /* restore saved parameters */ |
|
2808 while ((pm = (Param) ugetnode(restorelist))) { |
|
2809 if (pm->flags & PM_SPECIAL) { |
|
2810 Param tpm = (Param) paramtab->getnode(paramtab, pm->nam); |
|
2811 |
|
2812 DPUTS(!tpm || PM_TYPE(pm->flags) != PM_TYPE(tpm->flags) || |
|
2813 !(pm->flags & PM_SPECIAL), |
|
2814 "BUG: in restoring special parameters"); |
|
2815 tpm->flags = pm->flags; |
|
2816 switch (PM_TYPE(pm->flags)) { |
|
2817 case PM_SCALAR: |
|
2818 tpm->gsu.s->setfn(tpm, pm->u.str); |
|
2819 break; |
|
2820 case PM_INTEGER: |
|
2821 tpm->gsu.i->setfn(tpm, pm->u.val); |
|
2822 break; |
|
2823 case PM_EFLOAT: |
|
2824 case PM_FFLOAT: |
|
2825 tpm->gsu.f->setfn(tpm, pm->u.dval); |
|
2826 break; |
|
2827 case PM_ARRAY: |
|
2828 tpm->gsu.a->setfn(tpm, pm->u.arr); |
|
2829 break; |
|
2830 case PM_HASHED: |
|
2831 tpm->gsu.h->setfn(tpm, pm->u.hash); |
|
2832 break; |
|
2833 } |
|
2834 pm = tpm; |
|
2835 } else |
|
2836 paramtab->addnode(paramtab, pm->nam, pm); |
|
2837 if ((pm->flags & PM_EXPORTED) && ((s = getsparam(pm->nam)))) |
|
2838 addenv(pm, s); |
|
2839 } |
|
2840 } |
|
2841 } |
|
2842 |
|
2843 /* restore fds after redirecting a builtin */ |
|
2844 |
|
2845 /**/ |
|
2846 static void |
|
2847 fixfds(int *save) |
|
2848 { |
|
2849 int old_errno = errno; |
|
2850 int i; |
|
2851 |
|
2852 for (i = 0; i != 10; i++) |
|
2853 if (save[i] != -2) |
|
2854 redup(save[i], i); |
|
2855 errno = old_errno; |
|
2856 } |
|
2857 |
|
2858 /**/ |
|
2859 int |
|
2860 forklevel; |
|
2861 |
|
2862 /**/ |
|
2863 static void |
|
2864 entersubsh(int how, int cl, int fake, int revertpgrp) |
|
2865 { |
|
2866 int sig, monitor; |
|
2867 |
|
2868 if (cl != 2) |
|
2869 for (sig = 0; sig < VSIGCOUNT; sig++) |
|
2870 if (!(sigtrapped[sig] & ZSIG_FUNC)) |
|
2871 unsettrap(sig); |
|
2872 if (!(monitor = isset(MONITOR))) { |
|
2873 if (how & Z_ASYNC) { |
|
2874 settrap(SIGINT, NULL); |
|
2875 settrap(SIGQUIT, NULL); |
|
2876 if (isatty(0)) { |
|
2877 close(0); |
|
2878 if (open("/dev/null", O_RDWR | O_NOCTTY)) { |
|
2879 zerr("can't open /dev/null: %e", NULL, errno); |
|
2880 _exit(1); |
|
2881 } |
|
2882 } |
|
2883 } |
|
2884 } else if (thisjob != -1 && cl) { |
|
2885 if (jobtab[list_pipe_job].gleader && (list_pipe || list_pipe_child)) { |
|
2886 if (setpgrp(0L, jobtab[list_pipe_job].gleader) == -1 || |
|
2887 killpg(jobtab[list_pipe_job].gleader, 0) == -1) { |
|
2888 jobtab[list_pipe_job].gleader = |
|
2889 jobtab[thisjob].gleader = (list_pipe_child ? mypgrp : getpid()); |
|
2890 setpgrp(0L, jobtab[list_pipe_job].gleader); |
|
2891 if (how & Z_SYNC) |
|
2892 attachtty(jobtab[thisjob].gleader); |
|
2893 } |
|
2894 } |
|
2895 else if (!jobtab[thisjob].gleader || |
|
2896 setpgrp(0L, jobtab[thisjob].gleader) == -1) { |
|
2897 jobtab[thisjob].gleader = getpid(); |
|
2898 if (list_pipe_job != thisjob && |
|
2899 !jobtab[list_pipe_job].gleader) |
|
2900 jobtab[list_pipe_job].gleader = jobtab[thisjob].gleader; |
|
2901 setpgrp(0L, jobtab[thisjob].gleader); |
|
2902 if (how & Z_SYNC) |
|
2903 attachtty(jobtab[thisjob].gleader); |
|
2904 } |
|
2905 } |
|
2906 if (!fake) |
|
2907 subsh = 1; |
|
2908 if (revertpgrp && getpid() == mypgrp) |
|
2909 release_pgrp(); |
|
2910 if (SHTTY != -1) { |
|
2911 shout = NULL; |
|
2912 zclose(SHTTY); |
|
2913 SHTTY = -1; |
|
2914 } |
|
2915 if (isset(MONITOR)) { |
|
2916 signal_default(SIGTTOU); |
|
2917 signal_default(SIGTTIN); |
|
2918 signal_default(SIGTSTP); |
|
2919 } |
|
2920 if (interact) { |
|
2921 signal_default(SIGTERM); |
|
2922 if (!(sigtrapped[SIGINT] & ZSIG_IGNORED)) |
|
2923 signal_default(SIGINT); |
|
2924 } |
|
2925 if (!(sigtrapped[SIGQUIT] & ZSIG_IGNORED)) |
|
2926 signal_default(SIGQUIT); |
|
2927 opts[MONITOR] = opts[USEZLE] = 0; |
|
2928 zleactive = 0; |
|
2929 if (cl) |
|
2930 clearjobtab(monitor); |
|
2931 get_usage(); |
|
2932 forklevel = locallevel; |
|
2933 } |
|
2934 |
|
2935 /* close internal shell fds */ |
|
2936 |
|
2937 /**/ |
|
2938 mod_export void |
|
2939 closem(int how) |
|
2940 { |
|
2941 int i; |
|
2942 |
|
2943 for (i = 10; i <= max_zsh_fd; i++) |
|
2944 if (fdtable[i] && (!how || fdtable[i] == how)) |
|
2945 zclose(i); |
|
2946 } |
|
2947 |
|
2948 /* convert here document into a here string */ |
|
2949 |
|
2950 /**/ |
|
2951 char * |
|
2952 gethere(char *str, int typ) |
|
2953 { |
|
2954 char *buf; |
|
2955 int bsiz, qt = 0, strip = 0; |
|
2956 char *s, *t, *bptr, c; |
|
2957 |
|
2958 for (s = str; *s; s++) |
|
2959 if (INULL(*s)) { |
|
2960 qt = 1; |
|
2961 break; |
|
2962 } |
|
2963 quotesubst(str); |
|
2964 untokenize(str); |
|
2965 if (typ == REDIR_HEREDOCDASH) { |
|
2966 strip = 1; |
|
2967 while (*str == '\t') |
|
2968 str++; |
|
2969 } |
|
2970 bptr = buf = zalloc(bsiz = 256); |
|
2971 for (;;) { |
|
2972 t = bptr; |
|
2973 |
|
2974 while ((c = hgetc()) == '\t' && strip) |
|
2975 ; |
|
2976 for (;;) { |
|
2977 if (bptr == buf + bsiz) { |
|
2978 buf = realloc(buf, 2 * bsiz); |
|
2979 t = buf + bsiz - (bptr - t); |
|
2980 bptr = buf + bsiz; |
|
2981 bsiz *= 2; |
|
2982 } |
|
2983 if (lexstop || c == '\n') |
|
2984 break; |
|
2985 *bptr++ = c; |
|
2986 c = hgetc(); |
|
2987 } |
|
2988 *bptr = '\0'; |
|
2989 if (!strcmp(t, str)) |
|
2990 break; |
|
2991 if (lexstop) { |
|
2992 t = bptr; |
|
2993 break; |
|
2994 } |
|
2995 *bptr++ = '\n'; |
|
2996 } |
|
2997 if (t > buf && t[-1] == '\n') |
|
2998 t--; |
|
2999 *t = '\0'; |
|
3000 if (!qt) { |
|
3001 int ef = errflag; |
|
3002 |
|
3003 parsestr(buf); |
|
3004 |
|
3005 if (!errflag) |
|
3006 errflag = ef; |
|
3007 } |
|
3008 s = dupstring(buf); |
|
3009 zfree(buf, bsiz); |
|
3010 return s; |
|
3011 } |
|
3012 |
|
3013 /* open here string fd */ |
|
3014 |
|
3015 /**/ |
|
3016 static int |
|
3017 getherestr(struct redir *fn) |
|
3018 { |
|
3019 char *s, *t; |
|
3020 int fd, len; |
|
3021 |
|
3022 t = fn->name; |
|
3023 singsub(&t); |
|
3024 untokenize(t); |
|
3025 unmetafy(t, &len); |
|
3026 t[len++] = '\n'; |
|
3027 if ((fd = gettempfile(NULL, 1, &s)) < 0) |
|
3028 return -1; |
|
3029 write(fd, t, len); |
|
3030 close(fd); |
|
3031 fd = open(s, O_RDONLY | O_NOCTTY); |
|
3032 unlink(s); |
|
3033 return fd; |
|
3034 } |
|
3035 |
|
3036 /* $(...) */ |
|
3037 |
|
3038 /**/ |
|
3039 LinkList |
|
3040 getoutput(char *cmd, int qt) |
|
3041 { |
|
3042 Eprog prog; |
|
3043 int pipes[2]; |
|
3044 |
|
3045 #ifndef __SYMBIAN32__ |
|
3046 pid_t pid; |
|
3047 #endif |
|
3048 Wordcode pc; |
|
3049 int fd; |
|
3050 LinkList retval; |
|
3051 if (!(prog = parse_string(cmd))) |
|
3052 return NULL; |
|
3053 |
|
3054 pc = prog->prog; |
|
3055 if (prog != &dummy_eprog && |
|
3056 wc_code(pc[0]) == WC_LIST && (WC_LIST_TYPE(pc[0]) & Z_END) && |
|
3057 wc_code(pc[1]) == WC_SUBLIST && !WC_SUBLIST_FLAGS(pc[1]) && |
|
3058 WC_SUBLIST_TYPE(pc[1]) == WC_SUBLIST_END && |
|
3059 wc_code(pc[2]) == WC_PIPE && WC_PIPE_TYPE(pc[2]) == WC_PIPE_END && |
|
3060 wc_code(pc[3]) == WC_REDIR && WC_REDIR_TYPE(pc[3]) == REDIR_READ && |
|
3061 !pc[4] && |
|
3062 wc_code(pc[6]) == WC_SIMPLE && !WC_SIMPLE_ARGC(pc[6])) { |
|
3063 /* $(< word) */ |
|
3064 int stream; |
|
3065 char *s = dupstring(ecrawstr(prog, pc + 5, NULL)); |
|
3066 |
|
3067 singsub(&s); |
|
3068 if (errflag) |
|
3069 return NULL; |
|
3070 untokenize(s); |
|
3071 if ((stream = open(unmeta(s), O_RDONLY | O_NOCTTY)) == -1) { |
|
3072 zerr("%e: %s", s, errno); |
|
3073 return NULL; |
|
3074 } |
|
3075 return readoutput(stream, qt); |
|
3076 } |
|
3077 #ifndef __SYMBIAN32__ |
|
3078 mpipe(pipes); |
|
3079 child_block(); |
|
3080 cmdoutval = 0; |
|
3081 if ((cmdoutpid = pid = zfork(NULL)) == -1) { |
|
3082 /* fork error */ |
|
3083 zclose(pipes[0]); |
|
3084 zclose(pipes[1]); |
|
3085 errflag = 1; |
|
3086 cmdoutpid = 0; |
|
3087 child_unblock(); |
|
3088 return NULL; |
|
3089 } else if (pid) { |
|
3090 LinkList retval; |
|
3091 |
|
3092 zclose(pipes[1]); |
|
3093 retval = readoutput(pipes[0], qt); |
|
3094 fdtable[pipes[0]] = 0; |
|
3095 waitforpid(pid); /* unblocks */ |
|
3096 lastval = cmdoutval; |
|
3097 return retval; |
|
3098 } |
|
3099 /* pid == 0 */ |
|
3100 child_unblock(); |
|
3101 zclose(pipes[0]); |
|
3102 redup(pipes[1], 1); |
|
3103 opts[MONITOR] = 0; |
|
3104 entersubsh(Z_SYNC, 1, 0, 0); |
|
3105 cmdpush(CS_CMDSUBST); |
|
3106 |
|
3107 cmdpop(); |
|
3108 close(1); |
|
3109 _exit(lastval); |
|
3110 zerr("exit returned in child!!", NULL, 0); |
|
3111 kill(getpid(), SIGKILL); |
|
3112 #endif // __SYMBIAN32__ |
|
3113 |
|
3114 //execute the command within the same process space |
|
3115 mpipe(pipes); |
|
3116 fd = dup(1); /* Preserve stdout */ |
|
3117 fcntl(fd, F_SETFD, FD_CLOEXEC); |
|
3118 |
|
3119 redup(pipes[1], 1); |
|
3120 execode(prog, 0, 1); |
|
3121 |
|
3122 retval=readoutput(pipes[0], qt); |
|
3123 redup(fd, 1); |
|
3124 zclose(pipes[0]); |
|
3125 zclose(pipes[1]); |
|
3126 close(fd); |
|
3127 |
|
3128 return retval; |
|
3129 } |
|
3130 |
|
3131 /* read output of command substitution */ |
|
3132 |
|
3133 /**/ |
|
3134 mod_export LinkList |
|
3135 readoutput(int in, int qt) |
|
3136 { |
|
3137 LinkList ret; |
|
3138 char *buf, *ptr; |
|
3139 int bsiz, cnt = 0; |
|
3140 char c; |
|
3141 FILE *fin; |
|
3142 #ifdef __SYMBIAN32__ |
|
3143 struct timeval tv; |
|
3144 fd_set readfds; |
|
3145 |
|
3146 FD_ZERO(&readfds); |
|
3147 FD_SET(in, &readfds); |
|
3148 |
|
3149 tv.tv_sec = 0; |
|
3150 tv.tv_usec = 1; |
|
3151 |
|
3152 fin = fdopen(in, "r"); |
|
3153 ret = newlinklist(); |
|
3154 ptr = buf = (char *) hcalloc(bsiz = 64); |
|
3155 if(select(in+1, &readfds, NULL, NULL, &tv)==0) |
|
3156 { |
|
3157 goto dont_read; |
|
3158 } |
|
3159 #endif //__SYMBIAN32__ |
|
3160 |
|
3161 while ((read(in, &c, 1) >0) || errno == EINTR) { |
|
3162 #ifndef __SYMBIAN32__ |
|
3163 if (c == EOF) { |
|
3164 errno = 0; |
|
3165 clearerr(fin); |
|
3166 continue; |
|
3167 } |
|
3168 #endif |
|
3169 if (imeta(c)) { |
|
3170 *ptr++ = Meta; |
|
3171 c ^= 32; |
|
3172 cnt++; |
|
3173 } |
|
3174 if (++cnt >= bsiz) { |
|
3175 char *pp = (char *) hcalloc(bsiz *= 2); |
|
3176 |
|
3177 memcpy(pp, buf, cnt - 1); |
|
3178 ptr = (buf = pp) + cnt - 1; |
|
3179 } |
|
3180 *ptr++ = c; |
|
3181 #ifndef __SYMBIAN32__ |
|
3182 if (ptr[-1]=='\n') |
|
3183 { |
|
3184 break; |
|
3185 } |
|
3186 #else |
|
3187 FD_ZERO(&readfds); |
|
3188 FD_SET(in, &readfds); |
|
3189 if(select(in+1, &readfds, NULL, NULL, &tv)==0) |
|
3190 { |
|
3191 break; |
|
3192 } |
|
3193 #endif |
|
3194 } |
|
3195 |
|
3196 dont_read: |
|
3197 fclose(fin); |
|
3198 while (cnt && ptr[-1] == '\n') |
|
3199 ptr--, cnt--; |
|
3200 *ptr = '\0'; |
|
3201 if (qt) { |
|
3202 if (!cnt) { |
|
3203 *ptr++ = Nularg; |
|
3204 *ptr = '\0'; |
|
3205 } |
|
3206 addlinknode(ret, buf); |
|
3207 } else { |
|
3208 char **words = spacesplit(buf, 0, 1, 0); |
|
3209 |
|
3210 while (*words) { |
|
3211 if (isset(GLOBSUBST)) |
|
3212 shtokenize(*words); |
|
3213 addlinknode(ret, *words++); |
|
3214 } |
|
3215 } |
|
3216 return ret; |
|
3217 } |
|
3218 |
|
3219 /**/ |
|
3220 static Eprog |
|
3221 parsecmd(char *cmd) |
|
3222 { |
|
3223 char *str; |
|
3224 Eprog prog; |
|
3225 |
|
3226 for (str = cmd + 2; *str && *str != Outpar; str++); |
|
3227 if (!*str || cmd[1] != Inpar) { |
|
3228 zerr("oops.", NULL, 0); |
|
3229 return NULL; |
|
3230 } |
|
3231 *str = '\0'; |
|
3232 if (str[1] || !(prog = parse_string(cmd + 2))) { |
|
3233 zerr("parse error in process substitution", NULL, 0); |
|
3234 return NULL; |
|
3235 } |
|
3236 return prog; |
|
3237 } |
|
3238 |
|
3239 /* =(...) */ |
|
3240 |
|
3241 /**/ |
|
3242 char * |
|
3243 getoutputfile(char *cmd) |
|
3244 { |
|
3245 Eprog prog; |
|
3246 |
|
3247 #ifndef __SYMBIAN32__ |
|
3248 pid_t pid; |
|
3249 char *nam; |
|
3250 int fd; |
|
3251 |
|
3252 if (thisjob == -1) |
|
3253 return NULL; |
|
3254 if (!(prog = parsecmd(cmd))) |
|
3255 return NULL; |
|
3256 if (!(nam = gettempname(NULL, 0))) |
|
3257 return NULL; |
|
3258 |
|
3259 if (!jobtab[thisjob].filelist) |
|
3260 jobtab[thisjob].filelist = znewlinklist(); |
|
3261 zaddlinknode(jobtab[thisjob].filelist, nam); |
|
3262 |
|
3263 child_block(); |
|
3264 fd = open(nam, O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0600); |
|
3265 |
|
3266 if (fd < 0 || (cmdoutpid = pid = zfork(NULL)) == -1) { |
|
3267 /* fork or open error */ |
|
3268 child_unblock(); |
|
3269 return nam; |
|
3270 } else if (pid) { |
|
3271 int os; |
|
3272 |
|
3273 close(fd); |
|
3274 os = jobtab[thisjob].stat; |
|
3275 waitforpid(pid); |
|
3276 cmdoutval = 0; |
|
3277 jobtab[thisjob].stat = os; |
|
3278 return nam; |
|
3279 } |
|
3280 |
|
3281 /* pid == 0 */ |
|
3282 redup(fd, 1); |
|
3283 opts[MONITOR] = 0; |
|
3284 entersubsh(Z_SYNC, 1, 0, 0); |
|
3285 cmdpush(CS_CMDSUBST); |
|
3286 execode(prog, 0, 1); |
|
3287 cmdpop(); |
|
3288 close(1); |
|
3289 _exit(lastval); |
|
3290 zerr("exit returned in child!!", NULL, 0); |
|
3291 kill(getpid(), SIGKILL); |
|
3292 return NULL; |
|
3293 #else |
|
3294 st_exec stexec; |
|
3295 pthread_t testThread; |
|
3296 |
|
3297 if (!(prog = parsecmd(cmd))) |
|
3298 return NULL; |
|
3299 |
|
3300 stexec.dont_change_job=0; |
|
3301 stexec.exiting=1; |
|
3302 stexec.p=prog; |
|
3303 |
|
3304 pthread_create(&testThread, NULL, &execode_wrap, (void*)&stexec); |
|
3305 return NULL; |
|
3306 #endif |
|
3307 } |
|
3308 |
|
3309 #if !defined(PATH_DEV_FD) && defined(HAVE_FIFOS) |
|
3310 /* get a temporary named pipe */ |
|
3311 |
|
3312 static char * |
|
3313 namedpipe(void) |
|
3314 { |
|
3315 char *tnam = gettempname(NULL, 1); |
|
3316 |
|
3317 # ifdef HAVE_MKFIFO |
|
3318 if (mkfifo(tnam, 0600) < 0) |
|
3319 # else |
|
3320 if (mknod(tnam, 0010600, 0) < 0) |
|
3321 # endif |
|
3322 return NULL; |
|
3323 return tnam; |
|
3324 } |
|
3325 #endif /* ! PATH_DEV_FD && HAVE_FIFOS */ |
|
3326 |
|
3327 /* <(...) or >(...) */ |
|
3328 |
|
3329 /**/ |
|
3330 char * |
|
3331 getproc(char *cmd) |
|
3332 { |
|
3333 #if !defined(HAVE_FIFOS) && !defined(PATH_DEV_FD) |
|
3334 zerr("doesn't look like your system supports FIFOs.", NULL, 0); |
|
3335 return NULL; |
|
3336 #else |
|
3337 Eprog prog; |
|
3338 int out = *cmd == Inang; |
|
3339 |
|
3340 #ifndef __SYMBIAN32__ |
|
3341 char *pnam; |
|
3342 pid_t pid; |
|
3343 struct timeval bgtime; |
|
3344 |
|
3345 #ifndef PATH_DEV_FD |
|
3346 int fd; |
|
3347 if (thisjob == -1) |
|
3348 return NULL; |
|
3349 if (!(pnam = namedpipe())) |
|
3350 return NULL; |
|
3351 if (!(prog = parsecmd(cmd))) |
|
3352 return NULL; |
|
3353 if (!jobtab[thisjob].filelist) |
|
3354 jobtab[thisjob].filelist = znewlinklist(); |
|
3355 zaddlinknode(jobtab[thisjob].filelist, ztrdup(pnam)); |
|
3356 |
|
3357 if ((pid = zfork(&bgtime))) { |
|
3358 if (pid == -1) |
|
3359 return NULL; |
|
3360 if (!out) |
|
3361 addproc(pid, NULL, 1, &bgtime); |
|
3362 return pnam; |
|
3363 } |
|
3364 closem(0); |
|
3365 fd = open(pnam, out ? O_WRONLY | O_NOCTTY : O_RDONLY | O_NOCTTY); |
|
3366 if (fd == -1) { |
|
3367 zerr("can't open %s: %e", pnam, errno); |
|
3368 _exit(1); |
|
3369 } |
|
3370 entersubsh(Z_ASYNC, 1, 0, 0); |
|
3371 redup(fd, out); |
|
3372 #else /* PATH_DEV_FD */ |
|
3373 int pipes[2]; |
|
3374 |
|
3375 if (thisjob == -1) |
|
3376 return NULL; |
|
3377 pnam = hcalloc(strlen(PATH_DEV_FD) + 6); |
|
3378 if (!(prog = parsecmd(cmd))) |
|
3379 return NULL; |
|
3380 mpipe(pipes); |
|
3381 if ((pid = zfork(&bgtime))) { |
|
3382 sprintf(pnam, "%s/%d", PATH_DEV_FD, pipes[!out]); |
|
3383 zclose(pipes[out]); |
|
3384 if (pid == -1) |
|
3385 { |
|
3386 zclose(pipes[!out]); |
|
3387 return NULL; |
|
3388 } |
|
3389 fdtable[pipes[!out]] = 2; |
|
3390 if (!out) |
|
3391 { |
|
3392 addproc(pid, NULL, 1, &bgtime); |
|
3393 } |
|
3394 return pnam; |
|
3395 } |
|
3396 entersubsh(Z_ASYNC, 1, 0, 0); |
|
3397 redup(pipes[out], out); |
|
3398 closem(0); /* this closes pipes[!out] as well */ |
|
3399 |
|
3400 #endif /* PATH_DEV_FD */ |
|
3401 |
|
3402 cmdpush(CS_CMDSUBST); |
|
3403 execode(prog, 0, 1); |
|
3404 cmdpop(); |
|
3405 zclose(out); |
|
3406 _exit(lastval); |
|
3407 return NULL; |
|
3408 #else /*__SYMBIAN32__*/ |
|
3409 st_exec stexec; |
|
3410 pthread_t testThread; |
|
3411 |
|
3412 if (!(prog = parsecmd(cmd))) |
|
3413 return NULL; |
|
3414 |
|
3415 stexec.dont_change_job=0; |
|
3416 stexec.exiting=1; |
|
3417 stexec.p=prog; |
|
3418 |
|
3419 pthread_create(&testThread, NULL, &execode_wrap, (void*)&stexec); |
|
3420 return NULL; |
|
3421 #endif // __SYMBIAN32__ |
|
3422 #endif /* HAVE_FIFOS and PATH_DEV_FD not defined */ |
|
3423 } |
|
3424 |
|
3425 /* |
|
3426 * > >(...) or < <(...) (does not use named pipes) |
|
3427 * |
|
3428 * If the second argument is 1, this is part of |
|
3429 * an "exec < <(...)" or "exec > >(...)" and we shouldn't |
|
3430 * wait for the job to finish before continuing. |
|
3431 */ |
|
3432 |
|
3433 /**/ |
|
3434 static int |
|
3435 getpipe(char *cmd, int nullexec) |
|
3436 { |
|
3437 Eprog prog; |
|
3438 int out = *cmd == Inang; |
|
3439 |
|
3440 |
|
3441 #ifndef __SYMBIAN32__ |
|
3442 pid_t pid; |
|
3443 struct timeval bgtime; |
|
3444 int pipes[2]; |
|
3445 |
|
3446 if (!(prog = parsecmd(cmd))) |
|
3447 return -1; |
|
3448 |
|
3449 mpipe(pipes); |
|
3450 if ((pid = zfork(&bgtime))) { |
|
3451 zclose(pipes[out]); |
|
3452 if (pid == -1) { |
|
3453 zclose(pipes[!out]); |
|
3454 return -1; |
|
3455 } |
|
3456 if (!nullexec) |
|
3457 addproc(pid, NULL, 1, &bgtime); |
|
3458 return pipes[!out]; |
|
3459 } |
|
3460 entersubsh(Z_ASYNC, 1, 0, 0); |
|
3461 redup(pipes[out], out); |
|
3462 closem(0); /* this closes pipes[!out] as well */ |
|
3463 cmdpush(CS_CMDSUBST); |
|
3464 execode(prog, 0, 1); |
|
3465 cmdpop(); |
|
3466 _exit(lastval); |
|
3467 #else |
|
3468 st_exec stexec; |
|
3469 pthread_t testThread; |
|
3470 |
|
3471 if (!(prog = parsecmd(cmd))) |
|
3472 return -1; |
|
3473 |
|
3474 stexec.dont_change_job=0; |
|
3475 stexec.exiting=1; |
|
3476 stexec.p=prog; |
|
3477 |
|
3478 pthread_create(&testThread, NULL, &execode_wrap, (void*)&stexec); |
|
3479 #endif //__SYMBIAN32__ |
|
3480 return 0; |
|
3481 } |
|
3482 |
|
3483 /* open pipes with fds >= 10 */ |
|
3484 |
|
3485 /**/ |
|
3486 static void |
|
3487 mpipe(int *pp) |
|
3488 { |
|
3489 pipe(pp); |
|
3490 pp[0] = movefd(pp[0]); |
|
3491 pp[1] = movefd(pp[1]); |
|
3492 } |
|
3493 |
|
3494 /* |
|
3495 * Do process substitution with redirection |
|
3496 * |
|
3497 * If the second argument is 1, this is part of |
|
3498 * an "exec < <(...)" or "exec > >(...)" and we shouldn't |
|
3499 * wait for the job to finish before continuing. |
|
3500 */ |
|
3501 |
|
3502 /**/ |
|
3503 static void |
|
3504 spawnpipes(LinkList l, int nullexec) |
|
3505 { |
|
3506 LinkNode n; |
|
3507 Redir f; |
|
3508 char *str; |
|
3509 |
|
3510 n = firstnode(l); |
|
3511 for (; n; incnode(n)) { |
|
3512 f = (Redir) getdata(n); |
|
3513 if (f->type == REDIR_OUTPIPE || f->type == REDIR_INPIPE) { |
|
3514 str = f->name; |
|
3515 f->fd2 = getpipe(str, nullexec); |
|
3516 } |
|
3517 } |
|
3518 } |
|
3519 |
|
3520 extern int tracingcond; |
|
3521 |
|
3522 /* evaluate a [[ ... ]] */ |
|
3523 |
|
3524 /**/ |
|
3525 static int |
|
3526 execcond(Estate state, UNUSED(int do_exec)) |
|
3527 { |
|
3528 int stat; |
|
3529 |
|
3530 state->pc--; |
|
3531 if (isset(XTRACE)) { |
|
3532 printprompt4(); |
|
3533 fprintf(xtrerr, "[["); |
|
3534 tracingcond++; |
|
3535 } |
|
3536 cmdpush(CS_COND); |
|
3537 stat = evalcond(state, NULL); |
|
3538 /* |
|
3539 * 2 indicates a syntax error. For compatibility, turn this |
|
3540 * into a shell error. |
|
3541 */ |
|
3542 if (stat == 2) |
|
3543 errflag = 1; |
|
3544 cmdpop(); |
|
3545 if (isset(XTRACE)) { |
|
3546 fprintf(xtrerr, " ]]\n"); |
|
3547 fflush(xtrerr); |
|
3548 tracingcond--; |
|
3549 } |
|
3550 return stat; |
|
3551 } |
|
3552 |
|
3553 /* evaluate a ((...)) arithmetic command */ |
|
3554 |
|
3555 /**/ |
|
3556 static int |
|
3557 execarith(Estate state, UNUSED(int do_exec)) |
|
3558 { |
|
3559 char *e; |
|
3560 mnumber val = zero_mnumber; |
|
3561 int htok = 0; |
|
3562 |
|
3563 if (isset(XTRACE)) { |
|
3564 printprompt4(); |
|
3565 fprintf(xtrerr, "(("); |
|
3566 } |
|
3567 cmdpush(CS_MATH); |
|
3568 e = ecgetstr(state, EC_DUPTOK, &htok); |
|
3569 if (htok) |
|
3570 singsub(&e); |
|
3571 if (isset(XTRACE)) |
|
3572 fprintf(xtrerr, " %s", e); |
|
3573 |
|
3574 val = matheval(e); |
|
3575 |
|
3576 cmdpop(); |
|
3577 |
|
3578 if (isset(XTRACE)) { |
|
3579 fprintf(xtrerr, " ))\n"); |
|
3580 fflush(xtrerr); |
|
3581 } |
|
3582 errflag = 0; |
|
3583 /* should test for fabs(val.u.d) < epsilon? */ |
|
3584 return (val.type == MN_INTEGER) ? val.u.l == 0 : val.u.d == 0.0; |
|
3585 } |
|
3586 |
|
3587 /* perform time ... command */ |
|
3588 |
|
3589 /**/ |
|
3590 static int |
|
3591 exectime(Estate state, UNUSED(int do_exec)) |
|
3592 { |
|
3593 int jb; |
|
3594 |
|
3595 jb = thisjob; |
|
3596 if (WC_TIMED_TYPE(state->pc[-1]) == WC_TIMED_EMPTY) { |
|
3597 shelltime(); |
|
3598 return 0; |
|
3599 } |
|
3600 execpline(state, *state->pc++, Z_TIMED|Z_SYNC, 0); |
|
3601 thisjob = jb; |
|
3602 return lastval; |
|
3603 } |
|
3604 |
|
3605 /* Define a shell function */ |
|
3606 |
|
3607 /**/ |
|
3608 static int |
|
3609 execfuncdef(Estate state, UNUSED(int do_exec)) |
|
3610 { |
|
3611 Shfunc shf; |
|
3612 char *s; |
|
3613 int signum, nprg, sbeg, nstrs, npats, len, plen, i, htok = 0; |
|
3614 Wordcode beg = state->pc, end; |
|
3615 Eprog prog; |
|
3616 Patprog *pp; |
|
3617 LinkList names; |
|
3618 |
|
3619 end = beg + WC_FUNCDEF_SKIP(state->pc[-1]); |
|
3620 if (!(names = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { |
|
3621 state->pc = end; |
|
3622 return 0; |
|
3623 } |
|
3624 nprg = end - beg; |
|
3625 sbeg = *state->pc++; |
|
3626 nstrs = *state->pc++; |
|
3627 npats = *state->pc++; |
|
3628 |
|
3629 nprg = (end - state->pc); |
|
3630 plen = nprg * sizeof(wordcode); |
|
3631 len = plen + (npats * sizeof(Patprog)) + nstrs; |
|
3632 |
|
3633 if (htok) |
|
3634 execsubst(names); |
|
3635 |
|
3636 while ((s = (char *) ugetnode(names))) { |
|
3637 prog = (Eprog) zalloc(sizeof(*prog)); |
|
3638 prog->npats = npats; |
|
3639 prog->nref = 1; /* allocated from permanent storage */ |
|
3640 prog->len = len; |
|
3641 if (state->prog->dump) { |
|
3642 prog->flags = EF_MAP; |
|
3643 incrdumpcount(state->prog->dump); |
|
3644 prog->pats = pp = (Patprog *) zalloc(npats * sizeof(Patprog)); |
|
3645 prog->prog = state->pc; |
|
3646 prog->strs = state->strs + sbeg; |
|
3647 prog->dump = state->prog->dump; |
|
3648 } else { |
|
3649 prog->flags = EF_REAL; |
|
3650 prog->pats = pp = (Patprog *) zalloc(len); |
|
3651 prog->prog = (Wordcode) (prog->pats + npats); |
|
3652 prog->strs = (char *) (prog->prog + nprg); |
|
3653 prog->dump = NULL; |
|
3654 memcpy(prog->prog, state->pc, plen); |
|
3655 memcpy(prog->strs, state->strs + sbeg, nstrs); |
|
3656 } |
|
3657 for (i = npats; i--; pp++) |
|
3658 *pp = dummy_patprog1; |
|
3659 prog->shf = NULL; |
|
3660 |
|
3661 shf = (Shfunc) zalloc(sizeof(*shf)); |
|
3662 shf->funcdef = prog; |
|
3663 shf->flags = 0; |
|
3664 |
|
3665 /* is this shell function a signal trap? */ |
|
3666 if (!strncmp(s, "TRAP", 4) && |
|
3667 (signum = getsignum(s + 4)) != -1) { |
|
3668 if (settrap(signum, shf->funcdef)) { |
|
3669 freeeprog(shf->funcdef); |
|
3670 zfree(shf, sizeof(*shf)); |
|
3671 state->pc = end; |
|
3672 return 1; |
|
3673 } |
|
3674 sigtrapped[signum] |= ZSIG_FUNC; |
|
3675 |
|
3676 /* |
|
3677 * Remove the old node explicitly in case it has |
|
3678 * an alternative name |
|
3679 */ |
|
3680 removetrapnode(signum); |
|
3681 } |
|
3682 shfunctab->addnode(shfunctab, ztrdup(s), shf); |
|
3683 } |
|
3684 state->pc = end; |
|
3685 return 0; |
|
3686 } |
|
3687 |
|
3688 /* Main entry point to execute a shell function. */ |
|
3689 |
|
3690 /**/ |
|
3691 static void |
|
3692 execshfunc(Shfunc shf, LinkList args) |
|
3693 { |
|
3694 LinkList last_file_list = NULL; |
|
3695 unsigned char *ocs; |
|
3696 int ocsp, osfc; |
|
3697 |
|
3698 if (errflag) |
|
3699 return; |
|
3700 |
|
3701 if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob)) { |
|
3702 /* Without this deletejob the process table * |
|
3703 * would be filled by a recursive function. */ |
|
3704 last_file_list = jobtab[thisjob].filelist; |
|
3705 jobtab[thisjob].filelist = NULL; |
|
3706 deletejob(jobtab + thisjob); |
|
3707 } |
|
3708 |
|
3709 if (isset(XTRACE)) { |
|
3710 LinkNode lptr; |
|
3711 printprompt4(); |
|
3712 if (args) |
|
3713 for (lptr = firstnode(args); lptr; incnode(lptr)) { |
|
3714 if (lptr != firstnode(args)) |
|
3715 fputc(' ', xtrerr); |
|
3716 quotedzputs((char *)getdata(lptr), xtrerr); |
|
3717 } |
|
3718 fputc('\n', xtrerr); |
|
3719 fflush(xtrerr); |
|
3720 } |
|
3721 ocs = cmdstack; |
|
3722 ocsp = cmdsp; |
|
3723 cmdstack = (unsigned char *) zalloc(CMDSTACKSZ); |
|
3724 cmdsp = 0; |
|
3725 if ((osfc = sfcontext) == SFC_NONE) |
|
3726 sfcontext = SFC_DIRECT; |
|
3727 doshfunc(shf->nam, shf->funcdef, args, shf->flags, 0); |
|
3728 sfcontext = osfc; |
|
3729 free(cmdstack); |
|
3730 cmdstack = ocs; |
|
3731 cmdsp = ocsp; |
|
3732 |
|
3733 if (!list_pipe) |
|
3734 deletefilelist(last_file_list); |
|
3735 } |
|
3736 |
|
3737 /* Function to execute the special type of command that represents an * |
|
3738 * autoloaded shell function. The command structure tells us which * |
|
3739 * function it is. This function is actually called as part of the * |
|
3740 * execution of the autoloaded function itself, so when the function * |
|
3741 * has been autoloaded, its list is just run with no frills. */ |
|
3742 |
|
3743 /**/ |
|
3744 static int |
|
3745 execautofn(Estate state, UNUSED(int do_exec)) |
|
3746 { |
|
3747 Shfunc shf; |
|
3748 char *oldscriptname; |
|
3749 |
|
3750 if (!(shf = loadautofn(state->prog->shf, 1, 0))) |
|
3751 return 1; |
|
3752 |
|
3753 oldscriptname = scriptname; |
|
3754 scriptname = dupstring(shf->nam); |
|
3755 execode(shf->funcdef, 1, 0); |
|
3756 scriptname = oldscriptname; |
|
3757 |
|
3758 return lastval; |
|
3759 } |
|
3760 |
|
3761 /**/ |
|
3762 Shfunc |
|
3763 loadautofn(Shfunc shf, int fksh, int autol) |
|
3764 { |
|
3765 int noalias = noaliases, ksh = 1; |
|
3766 Eprog prog; |
|
3767 |
|
3768 pushheap(); |
|
3769 |
|
3770 noaliases = (shf->flags & PM_UNALIASED); |
|
3771 prog = getfpfunc(shf->nam, &ksh); |
|
3772 noaliases = noalias; |
|
3773 |
|
3774 if (ksh == 1) { |
|
3775 ksh = fksh; |
|
3776 if (ksh == 1) |
|
3777 ksh = (shf->flags & PM_KSHSTORED) ? 2 : |
|
3778 (shf->flags & PM_ZSHSTORED) ? 0 : 1; |
|
3779 } |
|
3780 |
|
3781 if (prog == &dummy_eprog) { |
|
3782 /* We're not actually in the function; decrement locallevel */ |
|
3783 locallevel--; |
|
3784 zwarn("%s: function definition file not found", shf->nam, 0); |
|
3785 locallevel++; |
|
3786 popheap(); |
|
3787 return NULL; |
|
3788 } |
|
3789 if (!prog) |
|
3790 return NULL; |
|
3791 if (ksh == 2 || (ksh == 1 && isset(KSHAUTOLOAD))) { |
|
3792 if (autol) { |
|
3793 prog->flags |= EF_RUN; |
|
3794 |
|
3795 freeeprog(shf->funcdef); |
|
3796 if (prog->flags & EF_MAP) |
|
3797 shf->funcdef = prog; |
|
3798 else |
|
3799 shf->funcdef = dupeprog(prog, 0); |
|
3800 shf->flags &= ~PM_UNDEFINED; |
|
3801 } else { |
|
3802 VARARR(char, n, strlen(shf->nam) + 1); |
|
3803 strcpy(n, shf->nam); |
|
3804 execode(prog, 1, 0); |
|
3805 shf = (Shfunc) shfunctab->getnode(shfunctab, n); |
|
3806 if (!shf || (shf->flags & PM_UNDEFINED)) { |
|
3807 /* We're not actually in the function; decrement locallevel */ |
|
3808 locallevel--; |
|
3809 zwarn("%s: function not defined by file", n, 0); |
|
3810 locallevel++; |
|
3811 popheap(); |
|
3812 return NULL; |
|
3813 } |
|
3814 } |
|
3815 } else { |
|
3816 freeeprog(shf->funcdef); |
|
3817 if (prog->flags & EF_MAP) |
|
3818 shf->funcdef = stripkshdef(prog, shf->nam); |
|
3819 else |
|
3820 shf->funcdef = dupeprog(stripkshdef(prog, shf->nam), 0); |
|
3821 shf->flags &= ~PM_UNDEFINED; |
|
3822 } |
|
3823 popheap(); |
|
3824 |
|
3825 return shf; |
|
3826 } |
|
3827 |
|
3828 /* |
|
3829 * execute a shell function |
|
3830 * |
|
3831 * If noreturnval is nonzero, then reset the current return |
|
3832 * value (lastval) to its value before the shell function |
|
3833 * was executed. However, in any case return the status value |
|
3834 * from the function (i.e. if noreturnval is not set, this |
|
3835 * will be the same as lastval). |
|
3836 */ |
|
3837 |
|
3838 /**/ |
|
3839 mod_export int |
|
3840 doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval) |
|
3841 { |
|
3842 char **tab, **x, *oargv0; |
|
3843 int oldzoptind, oldlastval, oldoptcind, oldnumpipestats, ret; |
|
3844 int *oldpipestats = NULL; |
|
3845 char saveopts[OPT_SIZE], *oldscriptname = scriptname, *fname = dupstring(name); |
|
3846 int obreaks; |
|
3847 struct funcstack fstack; |
|
3848 #ifdef MAX_FUNCTION_DEPTH |
|
3849 static int funcdepth; |
|
3850 #endif |
|
3851 |
|
3852 pushheap(); |
|
3853 |
|
3854 oargv0 = NULL; |
|
3855 obreaks = breaks;; |
|
3856 if (trapreturn < 0) |
|
3857 trapreturn--; |
|
3858 oldlastval = lastval; |
|
3859 oldnumpipestats = numpipestats; |
|
3860 if (noreturnval) { |
|
3861 /* |
|
3862 * Easiest to use the heap here since we're bracketed |
|
3863 * immediately by a pushheap/popheap pair. |
|
3864 */ |
|
3865 size_t bytes = sizeof(int)*numpipestats; |
|
3866 oldpipestats = (int *)zhalloc(bytes); |
|
3867 memcpy(oldpipestats, pipestats, bytes); |
|
3868 } |
|
3869 |
|
3870 starttrapscope(); |
|
3871 |
|
3872 tab = pparams; |
|
3873 if (!(flags & PM_UNDEFINED)) |
|
3874 scriptname = dupstring(name); |
|
3875 oldzoptind = zoptind; |
|
3876 zoptind = 1; |
|
3877 oldoptcind = optcind; |
|
3878 optcind = 0; |
|
3879 |
|
3880 /* We need to save the current options even if LOCALOPTIONS is * |
|
3881 * not currently set. That's because if it gets set in the * |
|
3882 * function we need to restore the original options on exit. */ |
|
3883 memcpy(saveopts, opts, sizeof(opts)); |
|
3884 |
|
3885 if (flags & PM_TAGGED) |
|
3886 opts[XTRACE] = 1; |
|
3887 opts[PRINTEXITVALUE] = 0; |
|
3888 if (doshargs) { |
|
3889 LinkNode node; |
|
3890 |
|
3891 node = doshargs->first; |
|
3892 pparams = x = (char **) zshcalloc(((sizeof *x) * |
|
3893 (1 + countlinknodes(doshargs)))); |
|
3894 if (isset(FUNCTIONARGZERO)) { |
|
3895 oargv0 = argzero; |
|
3896 argzero = ztrdup((char *) node->dat); |
|
3897 } |
|
3898 node = node->next; |
|
3899 for (; node; node = node->next, x++) |
|
3900 *x = ztrdup((char *) node->dat); |
|
3901 } else { |
|
3902 pparams = (char **) zshcalloc(sizeof *pparams); |
|
3903 if (isset(FUNCTIONARGZERO)) { |
|
3904 oargv0 = argzero; |
|
3905 argzero = ztrdup(argzero); |
|
3906 } |
|
3907 } |
|
3908 #ifdef MAX_FUNCTION_DEPTH |
|
3909 if(++funcdepth > MAX_FUNCTION_DEPTH) |
|
3910 { |
|
3911 zerr("maximum nested function level reached", NULL, 0); |
|
3912 goto undoshfunc; |
|
3913 } |
|
3914 #endif |
|
3915 fstack.name = dupstring(name); |
|
3916 fstack.prev = funcstack; |
|
3917 funcstack = &fstack; |
|
3918 |
|
3919 if (prog->flags & EF_RUN) { |
|
3920 Shfunc shf; |
|
3921 |
|
3922 prog->flags &= ~EF_RUN; |
|
3923 |
|
3924 runshfunc(prog, NULL, fstack.name); |
|
3925 |
|
3926 if (!(shf = (Shfunc) shfunctab->getnode(shfunctab, |
|
3927 (name = fname)))) { |
|
3928 zwarn("%s: function not defined by file", name, 0); |
|
3929 if (noreturnval) |
|
3930 errflag = 1; |
|
3931 else |
|
3932 lastval = 1; |
|
3933 goto doneshfunc; |
|
3934 } |
|
3935 prog = shf->funcdef; |
|
3936 } |
|
3937 runshfunc(prog, wrappers, fstack.name); |
|
3938 doneshfunc: |
|
3939 funcstack = fstack.prev; |
|
3940 #ifdef MAX_FUNCTION_DEPTH |
|
3941 undoshfunc: |
|
3942 --funcdepth; |
|
3943 #endif |
|
3944 if (retflag) { |
|
3945 retflag = 0; |
|
3946 breaks = obreaks; |
|
3947 } |
|
3948 freearray(pparams); |
|
3949 if (oargv0) { |
|
3950 zsfree(argzero); |
|
3951 argzero = oargv0; |
|
3952 } |
|
3953 pparams = tab; |
|
3954 optcind = oldoptcind; |
|
3955 zoptind = oldzoptind; |
|
3956 scriptname = oldscriptname; |
|
3957 |
|
3958 if (isset(LOCALOPTIONS)) { |
|
3959 /* restore all shell options except PRIVILEGED and RESTRICTED */ |
|
3960 saveopts[PRIVILEGED] = opts[PRIVILEGED]; |
|
3961 saveopts[RESTRICTED] = opts[RESTRICTED]; |
|
3962 memcpy(opts, saveopts, sizeof(opts)); |
|
3963 } else { |
|
3964 /* just restore a couple. */ |
|
3965 opts[XTRACE] = saveopts[XTRACE]; |
|
3966 opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE]; |
|
3967 opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS]; |
|
3968 } |
|
3969 |
|
3970 endtrapscope(); |
|
3971 |
|
3972 if (trapreturn < -1) |
|
3973 trapreturn++; |
|
3974 ret = lastval; |
|
3975 if (noreturnval) { |
|
3976 lastval = oldlastval; |
|
3977 numpipestats = oldnumpipestats; |
|
3978 memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats); |
|
3979 } |
|
3980 popheap(); |
|
3981 |
|
3982 if (exit_pending) { |
|
3983 if (locallevel) { |
|
3984 /* Still functions to return: force them to do so. */ |
|
3985 retflag = 1; |
|
3986 breaks = loops; |
|
3987 } else { |
|
3988 /* |
|
3989 * All functions finished: time to exit the shell. |
|
3990 * We already did the `stopmsg' test when the |
|
3991 * exit command was handled. |
|
3992 */ |
|
3993 stopmsg = 1; |
|
3994 zexit(exit_pending >> 1, 0); |
|
3995 } |
|
3996 } |
|
3997 |
|
3998 return ret; |
|
3999 } |
|
4000 |
|
4001 /* This finally executes a shell function and any function wrappers * |
|
4002 * defined by modules. This works by calling the wrapper function which * |
|
4003 * in turn has to call back this function with the arguments it gets. */ |
|
4004 |
|
4005 /**/ |
|
4006 mod_export void |
|
4007 runshfunc(Eprog prog, FuncWrap wrap, char *name) |
|
4008 { |
|
4009 int cont; |
|
4010 VARARR(char, ou, underscoreused); |
|
4011 |
|
4012 memcpy(ou, underscore, underscoreused); |
|
4013 |
|
4014 while (wrap) { |
|
4015 wrap->module->wrapper++; |
|
4016 cont = wrap->handler(prog, wrap->next, name); |
|
4017 wrap->module->wrapper--; |
|
4018 |
|
4019 if (!wrap->module->wrapper && |
|
4020 (wrap->module->flags & MOD_UNLOAD)) |
|
4021 unload_module(wrap->module, NULL); |
|
4022 |
|
4023 if (!cont) |
|
4024 return; |
|
4025 wrap = wrap->next; |
|
4026 } |
|
4027 startparamscope(); |
|
4028 execode(prog, 1, 0); |
|
4029 setunderscore(ou); |
|
4030 endparamscope(); |
|
4031 } |
|
4032 |
|
4033 /* Search fpath for an undefined function. Finds the file, and returns the * |
|
4034 * list of its contents. */ |
|
4035 |
|
4036 /**/ |
|
4037 Eprog |
|
4038 getfpfunc(char *s, int *ksh) |
|
4039 { |
|
4040 char **pp, buf[PATH_MAX]; |
|
4041 off_t len; |
|
4042 off_t rlen; |
|
4043 char *d; |
|
4044 Eprog r; |
|
4045 int fd; |
|
4046 |
|
4047 pp = fpath; |
|
4048 for (; *pp; pp++) { |
|
4049 if (strlen(*pp) + strlen(s) + 1 >= PATH_MAX) |
|
4050 continue; |
|
4051 if (**pp) |
|
4052 sprintf(buf, "%s/%s", *pp, s); |
|
4053 else |
|
4054 strcpy(buf, s); |
|
4055 if ((r = try_dump_file(*pp, s, buf, ksh))) |
|
4056 return r; |
|
4057 unmetafy(buf, NULL); |
|
4058 if (!access(buf, R_OK) && (fd = open(buf, O_RDONLY | O_NOCTTY)) != -1) { |
|
4059 if ((len = lseek(fd, 0, 2)) != -1) { |
|
4060 d = (char *) zalloc(len + 1); |
|
4061 lseek(fd, 0, 0); |
|
4062 if ((rlen = read(fd, d, len)) >= 0) { |
|
4063 char *oldscriptname = scriptname; |
|
4064 |
|
4065 close(fd); |
|
4066 d[rlen] = '\0'; |
|
4067 d = metafy(d, rlen, META_REALLOC); |
|
4068 |
|
4069 scriptname = dupstring(s); |
|
4070 r = parse_string(d); |
|
4071 scriptname = oldscriptname; |
|
4072 |
|
4073 zfree(d, len + 1); |
|
4074 |
|
4075 return r; |
|
4076 } else |
|
4077 close(fd); |
|
4078 |
|
4079 zfree(d, len + 1); |
|
4080 } else |
|
4081 close(fd); |
|
4082 } |
|
4083 } |
|
4084 return &dummy_eprog; |
|
4085 } |
|
4086 |
|
4087 /* Handle the most common type of ksh-style autoloading, when doing a * |
|
4088 * zsh-style autoload. Given the list read from an autoload file, and the * |
|
4089 * name of the function being defined, check to see if the file consists * |
|
4090 * entirely of a single definition for that function. If so, use the * |
|
4091 * contents of that definition. Otherwise, use the entire file. */ |
|
4092 |
|
4093 /**/ |
|
4094 Eprog |
|
4095 stripkshdef(Eprog prog, char *name) |
|
4096 { |
|
4097 Wordcode pc = prog->prog; |
|
4098 wordcode code; |
|
4099 |
|
4100 if (!prog) |
|
4101 return NULL; |
|
4102 code = *pc++; |
|
4103 if (wc_code(code) != WC_LIST || |
|
4104 (WC_LIST_TYPE(code) & (Z_SYNC|Z_END|Z_SIMPLE)) != (Z_SYNC|Z_END|Z_SIMPLE)) |
|
4105 return prog; |
|
4106 pc++; |
|
4107 code = *pc++; |
|
4108 if (wc_code(code) != WC_FUNCDEF || |
|
4109 *pc != 1 || strcmp(name, ecrawstr(prog, pc + 1, NULL))) |
|
4110 return prog; |
|
4111 |
|
4112 { |
|
4113 Eprog ret; |
|
4114 Wordcode end = pc + WC_FUNCDEF_SKIP(code); |
|
4115 int sbeg = pc[2], nstrs = pc[3], nprg, npats = pc[4], plen, len, i; |
|
4116 Patprog *pp; |
|
4117 |
|
4118 pc += 5; |
|
4119 |
|
4120 nprg = end - pc; |
|
4121 plen = nprg * sizeof(wordcode); |
|
4122 len = plen + (npats * sizeof(Patprog)) + nstrs; |
|
4123 |
|
4124 if (prog->flags & EF_MAP) { |
|
4125 ret = prog; |
|
4126 free(prog->pats); |
|
4127 ret->pats = pp = (Patprog *) zalloc(npats * sizeof(Patprog)); |
|
4128 ret->prog = pc; |
|
4129 ret->strs = prog->strs + sbeg; |
|
4130 } else { |
|
4131 ret = (Eprog) zhalloc(sizeof(*ret)); |
|
4132 ret->flags = EF_HEAP; |
|
4133 ret->pats = pp = (Patprog *) zhalloc(len); |
|
4134 ret->prog = (Wordcode) (ret->pats + npats); |
|
4135 ret->strs = (char *) (ret->prog + nprg); |
|
4136 memcpy(ret->prog, pc, plen); |
|
4137 memcpy(ret->strs, prog->strs + sbeg, nstrs); |
|
4138 ret->dump = NULL; |
|
4139 } |
|
4140 ret->len = len; |
|
4141 ret->npats = npats; |
|
4142 for (i = npats; i--; pp++) |
|
4143 *pp = dummy_patprog1; |
|
4144 ret->shf = NULL; |
|
4145 |
|
4146 return ret; |
|
4147 } |
|
4148 } |
|
4149 |
|
4150 /* check to see if AUTOCD applies here */ |
|
4151 |
|
4152 /**/ |
|
4153 static char * |
|
4154 cancd(char *s) |
|
4155 { |
|
4156 int nocdpath = s[0] == '.' && |
|
4157 (s[1] == '/' || !s[1] || (s[1] == '.' && (s[2] == '/' || !s[1]))); |
|
4158 char *t; |
|
4159 |
|
4160 if (*s != '/') { |
|
4161 char sbuf[PATH_MAX], **cp; |
|
4162 |
|
4163 if (cancd2(s)) |
|
4164 return s; |
|
4165 if (access(unmeta(s), X_OK) == 0) |
|
4166 return NULL; |
|
4167 if (!nocdpath) |
|
4168 for (cp = cdpath; *cp; cp++) { |
|
4169 if (strlen(*cp) + strlen(s) + 1 >= PATH_MAX) |
|
4170 continue; |
|
4171 if (**cp) |
|
4172 sprintf(sbuf, "%s/%s", *cp, s); |
|
4173 else |
|
4174 strcpy(sbuf, s); |
|
4175 if (cancd2(sbuf)) { |
|
4176 doprintdir = -1; |
|
4177 return dupstring(sbuf); |
|
4178 } |
|
4179 } |
|
4180 if ((t = cd_able_vars(s))) { |
|
4181 if (cancd2(t)) { |
|
4182 doprintdir = -1; |
|
4183 return t; |
|
4184 } |
|
4185 } |
|
4186 return NULL; |
|
4187 } |
|
4188 return cancd2(s) ? s : NULL; |
|
4189 } |
|
4190 |
|
4191 /**/ |
|
4192 static int |
|
4193 cancd2(char *s) |
|
4194 { |
|
4195 struct stat buf; |
|
4196 char *us, *us2 = NULL; |
|
4197 int ret; |
|
4198 |
|
4199 /* |
|
4200 * If CHASEDOTS and CHASELINKS are not set, we want to rationalize the |
|
4201 * path by removing foo/.. combinations in the logical rather than |
|
4202 * the physical path. If either is set, we test the physical path. |
|
4203 */ |
|
4204 if (!isset(CHASEDOTS) && !isset(CHASELINKS)) { |
|
4205 if (*s != '/') |
|
4206 us = tricat(pwd[1] ? pwd : "", "/", s); |
|
4207 else |
|
4208 us = ztrdup(s); |
|
4209 fixdir(us2 = us); |
|
4210 } else |
|
4211 us = unmeta(s); |
|
4212 ret = !(access(us, X_OK) || stat(us, &buf) || !S_ISDIR(buf.st_mode)); |
|
4213 if (us2) |
|
4214 free(us2); |
|
4215 return ret; |
|
4216 } |
|
4217 |
|
4218 /**/ |
|
4219 void |
|
4220 execsave(void) |
|
4221 { |
|
4222 struct execstack *es; |
|
4223 |
|
4224 es = (struct execstack *) malloc(sizeof(struct execstack)); |
|
4225 es->args = args; |
|
4226 es->list_pipe_pid = list_pipe_pid; |
|
4227 es->nowait = nowait; |
|
4228 es->pline_level = pline_level; |
|
4229 es->list_pipe_child = list_pipe_child; |
|
4230 es->list_pipe_job = list_pipe_job; |
|
4231 strcpy(es->list_pipe_text, list_pipe_text); |
|
4232 es->lastval = lastval; |
|
4233 es->noeval = noeval; |
|
4234 es->badcshglob = badcshglob; |
|
4235 es->cmdoutpid = cmdoutpid; |
|
4236 es->cmdoutval = cmdoutval; |
|
4237 es->trapreturn = trapreturn; |
|
4238 es->noerrs = noerrs; |
|
4239 es->subsh_close = subsh_close; |
|
4240 es->underscore = ztrdup(underscore); |
|
4241 es->next = exstack; |
|
4242 exstack = es; |
|
4243 noerrs = cmdoutpid = 0; |
|
4244 } |
|
4245 |
|
4246 /**/ |
|
4247 void |
|
4248 execrestore(void) |
|
4249 { |
|
4250 struct execstack *en; |
|
4251 |
|
4252 DPUTS(!exstack, "BUG: execrestore() without execsave()"); |
|
4253 args = exstack->args; |
|
4254 list_pipe_pid = exstack->list_pipe_pid; |
|
4255 nowait = exstack->nowait; |
|
4256 pline_level = exstack->pline_level; |
|
4257 list_pipe_child = exstack->list_pipe_child; |
|
4258 list_pipe_job = exstack->list_pipe_job; |
|
4259 strcpy(list_pipe_text, exstack->list_pipe_text); |
|
4260 lastval = exstack->lastval; |
|
4261 noeval = exstack->noeval; |
|
4262 badcshglob = exstack->badcshglob; |
|
4263 cmdoutpid = exstack->cmdoutpid; |
|
4264 cmdoutval = exstack->cmdoutval; |
|
4265 trapreturn = exstack->trapreturn; |
|
4266 noerrs = exstack->noerrs; |
|
4267 subsh_close = exstack->subsh_close; |
|
4268 setunderscore(exstack->underscore); |
|
4269 zsfree(exstack->underscore); |
|
4270 en = exstack->next; |
|
4271 free(exstack); |
|
4272 exstack = en; |
|
4273 } |