1 /* Yash: yet another shell */
2 /* exec.c: command execution */
3 /* (C) 2007-2020 magicant */
4
5 /* This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18
19 #include "common.h"
20 #include "exec.h"
21 #include <assert.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #if HAVE_GETTEXT
25 # include <libintl.h>
26 #endif
27 #include <limits.h>
28 #include <math.h>
29 #if HAVE_PATHS_H
30 # include <paths.h>
31 #endif
32 #include <signal.h>
33 #include <stdbool.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/times.h>
39 #include <unistd.h>
40 #include <wchar.h>
41 #include "alias.h"
42 #include "builtin.h"
43 #include "expand.h"
44 #if YASH_ENABLE_HISTORY
45 # include "history.h"
46 #endif
47 #include "input.h"
48 #include "job.h"
49 #include "option.h"
50 #include "parser.h"
51 #include "path.h"
52 #include "plist.h"
53 #include "redir.h"
54 #include "sig.h"
55 #include "strbuf.h"
56 #include "util.h"
57 #include "variable.h"
58 #include "xfnmatch.h"
59 #include "yash.h"
60 #if YASH_ENABLE_DOUBLE_BRACKET
61 # include "builtins/test.h"
62 #endif
63 #if YASH_ENABLE_LINEEDIT
64 # include "lineedit/complete.h"
65 # include "lineedit/lineedit.h"
66 #endif
67
68
69 /* type of command execution */
70 typedef enum {
71 E_NORMAL, /* normal execution */
72 E_ASYNC, /* asynchronous execution */
73 E_SELF, /* execution in the shell's own process */
74 } exec_T;
75
76 /* info about file descriptors of pipes */
77 typedef struct pipeinfo_T {
78 int pi_fromprevfd; /* reading end of the pipe from the previous process */
79 int pi_tonextfds[2]; /* both ends of the pipe to the next process */
80 /* -1 is assigned to unused members. */
81 } pipeinfo_T;
82 #define PIPEINFO_INIT { -1, { -1, -1 }, }
83
84 /* values used to specify the behavior of command search. */
85 typedef enum srchcmdtype_T {
86 SCT_EXTERNAL = 1 << 0, /* search for an external command */
87 SCT_BUILTIN = 1 << 1, /* search for a built-in */
88 SCT_FUNCTION = 1 << 2, /* search for a function */
89 SCT_ALL = 1 << 3, /* search all */
90 SCT_STDPATH = 1 << 4, /* search the standard PATH */
91 SCT_CHECK = 1 << 5, /* check command existence */
92 } srchcmdtype_T;
93
94 typedef enum cmdtype_T {
95 CT_NONE,
96 CT_EXTERNALPROGRAM,
97 CT_SPECIALBUILTIN,
98 CT_SEMISPECIALBUILTIN,
99 CT_REGULARBUILTIN,
100 CT_FUNCTION,
101 } cmdtype_T;
102
103 /* info about a simple command to execute */
104 typedef struct commandinfo_T {
105 cmdtype_T type; /* type of command */
106 union {
107 const char *path; /* command path (for external program) */
108 main_T *builtin; /* body of built-in */
109 command_T *function; /* body of function */
110 } value;
111 } commandinfo_T;
112 #define ci_path value.path
113 #define ci_builtin value.builtin
114 #define ci_function value.function
115
116 /* result of `fork_and_wait' */
117 typedef struct fork_and_wait_T {
118 pid_t cpid; /* child process ID */
119 wchar_t **namep; /* where to place the job name */
120 } fork_and_wait_T;
121
122 typedef enum exception_T {
123 E_NONE,
124 E_CONTINUE,
125 E_RETURN,
126 E_BREAK_ITERATION,
127 E_CONTINUE_ITERATION,
128 } exception_T;
129
130 /* state of currently executed loop */
131 typedef struct execstate_T {
132 unsigned loopnest; /* level of nested loops */
133 unsigned breakloopnest; /* target level of "break" */
134 bool noreturn; /* true when the "return" built-in is not allowed */
135 bool iterating; /* true when iterative execution is ongoing */
136 } execstate_T;
137
138 static void exec_pipelines(const pipeline_T *p, bool finally_exit);
139 static void exec_pipelines_async(const pipeline_T *p)
140 __attribute__((nonnull));
141
142 static void exec_commands(command_T *cs, exec_T type)
143 __attribute__((nonnull));
144 static inline size_t number_of_commands_in_pipeline(const command_T *c)
145 __attribute__((nonnull,pure,warn_unused_result));
146 static void apply_errexit_errreturn(const command_T *c);
147 static bool is_errexit_condition(void)
148 __attribute__((pure));
149 static bool is_errreturn_condition(void)
150 __attribute__((pure));
151 static bool is_err_condition_for(const command_T *c)
152 __attribute__((pure));
153 static inline void next_pipe(pipeinfo_T *pi, bool next)
154 __attribute__((nonnull));
155 static inline void connect_pipes(pipeinfo_T *pi)
156 __attribute__((nonnull));
157
158 static void exec_one_command(command_T *c, bool finally_exit)
159 __attribute__((nonnull));
160 static void exec_simple_command(const command_T *c, bool finally_exit)
161 __attribute__((nonnull));
162 static bool exec_simple_command_without_words(const command_T *c)
163 __attribute__((nonnull,warn_unused_result));
164 static bool exec_simple_command_with_words(
165 const command_T *c, int argc, void **argv, bool finally_exit)
166 __attribute__((nonnull,warn_unused_result));
167 static void print_xtrace(void *const *argv);
168 static void search_command(
169 const char *restrict name, const wchar_t *restrict wname,
170 commandinfo_T *restrict ci, enum srchcmdtype_T type)
171 __attribute__((nonnull));
172 static inline bool is_special_builtin(const char *cmdname)
173 __attribute__((nonnull,pure));
174 static bool command_not_found_handler(void *const *argv)
175 __attribute__((nonnull));
176 static wchar_t **invoke_simple_command(const commandinfo_T *ci,
177 int argc, char *argv0, void **argv, bool finally_exit)
178 __attribute__((nonnull,warn_unused_result));
179 static void exec_external_program(
180 const char *path, int argc, char *argv0, void **argv, char **envs)
181 __attribute__((nonnull));
182 static inline int xexecve(
183 const char *path, char *const *argv, char *const *envp)
184 __attribute__((nonnull(1)));
185 static void exec_fall_back_on_sh(
186 int argc, char *const *argv, char *const *env, const char *path)
187 __attribute__((nonnull(2,3,4)));
188 static void exec_function_body(
189 command_T *body, void *const *args, bool finally_exit, bool complete)
190 __attribute__((nonnull));
191
192 static void exec_nonsimple_command(command_T *c, bool finally_exit)
193 __attribute__((nonnull));
194 static void exec_if(const command_T *c, bool finally_exit)
195 __attribute__((nonnull));
196 static inline bool exec_condition(const and_or_T *c);
197 static void exec_for(const command_T *c, bool finally_exit)
198 __attribute__((nonnull));
199 static void exec_while(const command_T *c, bool finally_exit)
200 __attribute__((nonnull));
201 static void exec_case(const command_T *c, bool finally_exit)
202 __attribute__((nonnull));
203 static void exec_funcdef(const command_T *c, bool finally_exit)
204 __attribute__((nonnull));
205
206 static fork_and_wait_T fork_and_wait(sigtype_T sigtype)
207 __attribute__((warn_unused_result));
208 static void become_child(sigtype_T sigtype);
209
210 static int exec_iteration(void *const *commands, const char *codename)
211 __attribute__((nonnull));
212
213
214 /* exit status of the last command */
215 int laststatus = Exit_SUCCESS;
216 /* exit status of the command preceding the currently executed trap action */
217 int savelaststatus = -1; // -1 if not in a trap handler
218 /* exit status of the last command substitution */
219 static int lastcmdsubstatus;
220 /* exit status of the command that immediately preceded the EXIT trap. */
221 int exitstatus = -1; // -1 if not executing the EXIT trap
222 /* the process ID of the last asynchronous list */
223 pid_t lastasyncpid;
224
225 /* This flag is set to true while the shell is executing the condition of an if-
226 * statement, an and-or list, etc. to suppress the effect of the "errexit" and
227 * "errreturn" options. */
228 static bool suppresserrexit = false, suppresserrreturn = false;
229
230 /* state of currently executed loop */
231 static execstate_T execstate;
232 /* exceptional jump to be done (other than "break") */
233 static exception_T exception;
234
235 /* This flag is set when a special built-in is executed as such. */
236 bool special_builtin_executed;
237
238 /* This flag is set while the "exec" built-in is executed. */
239 static bool exec_builtin_executed = false;
240
241 /* True while executing auxiliary commands such as $PROMPT_COMMAND and
242 * $COMMAND_NOT_FOUND_HANDLER. */
243 bool is_executing_auxiliary = false;
244
245 /* the last assignment. */
246 static const assign_T *last_assign;
247
248 /* a buffer for xtrace.
249 * When assignments are performed while executing a simple command, the trace
250 * is appended to this buffer. Each trace of an assignment must be prefixed
251 * with a space to separate it with the previous one. The first space will be
252 * trimmed when the buffer is flushed to the standard error. */
253 static xwcsbuf_T xtrace_buffer = { .contents = NULL };
254
255
256 /* Resets `execstate' to the initial state. */
reset_execstate(bool reset_iteration)257 void reset_execstate(bool reset_iteration)
258 {
259 execstate.loopnest = 0;
260 execstate.breakloopnest = 0;
261 execstate.noreturn = false;
262 if (reset_iteration)
263 execstate.iterating = false;
264 }
265
266 /* Saves the current `execstate' and returns it.
267 * You typically call `reset_execstate' after calling this function. */
save_execstate(void)268 execstate_T *save_execstate(void)
269 {
270 execstate_T *save = xmalloc(sizeof execstate);
271 *save = execstate;
272 return save;
273 }
274
275 /* Restores `execstate' to `save' and frees `save'. */
restore_execstate(execstate_T * save)276 void restore_execstate(execstate_T *save)
277 {
278 execstate = *save;
279 free(save);
280 }
281
282 /* Disables the "return" built-in in the current `execstate'. */
disable_return(void)283 void disable_return(void)
284 {
285 execstate.noreturn = true;
286 }
287
288 /* If we're returning, clear the flag. */
cancel_return(void)289 void cancel_return(void)
290 {
291 if (exception == E_RETURN)
292 exception = E_NONE;
293 }
294
295 /* Returns true iff we're breaking/continuing/returning now. */
need_break(void)296 bool need_break(void)
297 {
298 return execstate.breakloopnest < execstate.loopnest
299 || exception != E_NONE
300 || is_interrupted();
301 }
302
303
304 /* Executes the and-or lists.
305 * If `finally_exit' is true, the shell exits after execution. */
exec_and_or_lists(const and_or_T * a,bool finally_exit)306 void exec_and_or_lists(const and_or_T *a, bool finally_exit)
307 {
308 while (a != NULL && !need_break()) {
309 if (!a->ao_async)
310 exec_pipelines(a->ao_pipelines, finally_exit && !a->next);
311 else
312 exec_pipelines_async(a->ao_pipelines);
313
314 a = a->next;
315 }
316 if (finally_exit)
317 exit_shell();
318 }
319
320 /* Executes the pipelines. */
exec_pipelines(const pipeline_T * p,bool finally_exit)321 void exec_pipelines(const pipeline_T *p, bool finally_exit)
322 {
323 for (bool first = true;
324 p != NULL && !need_break();
325 p = p->next, first = false) {
326 if (!first && p->pl_cond == (laststatus != Exit_SUCCESS))
327 continue;
328
329 bool savesee = suppresserrexit, saveser = suppresserrreturn;
330 bool suppress = p->pl_neg || p->next != NULL;
331 suppresserrexit |= suppress;
332 suppresserrreturn |= suppress;
333
334 bool self = finally_exit && !p->next && !p->pl_neg;
335 exec_commands(p->pl_commands, self ? E_SELF : E_NORMAL);
336 if (p->pl_neg) {
337 if (laststatus == Exit_SUCCESS)
338 laststatus = Exit_FAILURE;
339 else
340 laststatus = Exit_SUCCESS;
341 }
342
343 suppresserrexit = savesee, suppresserrreturn = saveser;
344 }
345 if (finally_exit)
346 exit_shell();
347 }
348
349 /* Executes the pipelines asynchronously. */
exec_pipelines_async(const pipeline_T * p)350 void exec_pipelines_async(const pipeline_T *p)
351 {
352 if (p->next == NULL && !p->pl_neg) {
353 exec_commands(p->pl_commands, E_ASYNC);
354 return;
355 }
356
357 pid_t cpid = fork_and_reset(0, false, t_quitint);
358
359 if (cpid > 0) {
360 /* parent process: add a new job */
361 job_T *job = xmalloc(add(sizeof *job, sizeof *job->j_procs));
362 process_T *ps = job->j_procs;
363
364 ps->pr_pid = cpid;
365 ps->pr_status = JS_RUNNING;
366 ps->pr_statuscode = 0;
367 ps->pr_name = pipelines_to_wcs(p);
368
369 job->j_pgid = doing_job_control_now ? cpid : 0;
370 job->j_status = JS_RUNNING;
371 job->j_statuschanged = true;
372 job->j_legacy = false;
373 job->j_nonotify = false;
374 job->j_pcount = 1;
375
376 set_active_job(job);
377 add_job(shopt_curasync);
378 laststatus = Exit_SUCCESS;
379 lastasyncpid = cpid;
380 } else if (cpid == 0) {
381 /* child process: execute the commands and then exit */
382 maybe_redirect_stdin_to_devnull();
383 exec_pipelines(p, true);
384 assert(false);
385 } else {
386 /* fork failure */
387 laststatus = Exit_NOEXEC;
388 }
389 }
390
391 /* Executes the commands in a pipeline. */
exec_commands(command_T * const cs,exec_T type)392 void exec_commands(command_T *const cs, exec_T type)
393 {
394 size_t count = number_of_commands_in_pipeline(cs);
395 assert(count > 0);
396
397 bool short_circuit =
398 type == E_SELF && !doing_job_control_now && !any_trap_set &&
399 (count == 1 || !shopt_pipefail);
400
401 if (count == 1 && type != E_ASYNC) {
402 exec_one_command(cs, /* finally_exit = */ short_circuit);
403 goto done;
404 }
405
406 /* fork a child process for each command in the pipeline */
407 pid_t pgid = 0;
408 pipeinfo_T pipe = PIPEINFO_INIT;
409 job_T *job = xmallocs(sizeof *job, count, sizeof *job->j_procs);
410 command_T *c;
411 process_T *p;
412 int forkstatus = Exit_SUCCESS;
413 for (c = cs, p = job->j_procs; c != NULL; c = c->next, p++) {
414 bool is_last = c->next == NULL;
415 next_pipe(&pipe, !is_last);
416
417 if (is_last && short_circuit)
418 goto exec_one_command; /* skip forking */
419
420 sigtype_T sigtype = (type == E_ASYNC) ? t_quitint : 0;
421 pid_t pid = fork_and_reset(pgid, type == E_NORMAL, sigtype);
422 if (pid == 0) {
423 exec_one_command: /* child process */
424 free(job);
425 connect_pipes(&pipe);
426 if (type == E_ASYNC && pipe.pi_fromprevfd < 0)
427 maybe_redirect_stdin_to_devnull();
428 exec_one_command(c, true);
429 assert(false);
430 } else if (pid >= 0) {
431 /* parent process: fork succeeded */
432 if (pgid == 0)
433 pgid = pid;
434 p->pr_pid = pid;
435 p->pr_status = JS_RUNNING;
436 // p->pr_statuscode = ?; // The process is still running.
437 p->pr_name = NULL; // The actual name is given later.
438 } else {
439 /* parent process: fork failed */
440 p->pr_pid = 0;
441 p->pr_status = JS_DONE;
442 p->pr_statuscode = forkstatus = Exit_NOEXEC;
443 p->pr_name = NULL;
444 }
445 }
446
447 assert(pipe.pi_tonextfds[PIPE_IN] < 0);
448 assert(pipe.pi_tonextfds[PIPE_OUT] < 0);
449 if (pipe.pi_fromprevfd >= 0)
450 xclose(pipe.pi_fromprevfd); /* close the leftover pipe */
451
452 /* establish the job and wait for it */
453 job->j_pgid = doing_job_control_now ? pgid : 0;
454 job->j_status = JS_RUNNING;
455 job->j_statuschanged = true;
456 job->j_legacy = false;
457 job->j_nonotify = false;
458 job->j_pcount = count;
459 set_active_job(job);
460 if (type != E_ASYNC) {
461 wait_for_job(ACTIVE_JOBNO, doing_job_control_now, false, false);
462 if (doing_job_control_now)
463 put_foreground(shell_pgid);
464 laststatus = calc_status_of_job(job);
465 } else {
466 laststatus = forkstatus;
467 lastasyncpid = job->j_procs[count - 1].pr_pid;
468 }
469
470 if (job->j_status == JS_DONE) {
471 notify_signaled_job(ACTIVE_JOBNO);
472 remove_job(ACTIVE_JOBNO);
473 } else {
474 /* name the job processes */
475 for (c = cs, p = job->j_procs; c != NULL; c = c->next, p++)
476 p->pr_name = command_to_wcs(c, false);
477
478 /* remember the suspended job */
479 add_job(type == E_NORMAL || shopt_curasync);
480 }
481
482 done:
483 handle_signals();
484
485 apply_errexit_errreturn(cs);
486
487 if (type == E_SELF)
488 exit_shell();
489 }
490
number_of_commands_in_pipeline(const command_T * c)491 size_t number_of_commands_in_pipeline(const command_T *c)
492 {
493 size_t count = 1;
494 while ((c = c->next) != NULL)
495 count++;
496 return count;
497 }
498
499 /* Tests the current condition for "errexit" and "errreturn" and then performs
500 * exit or return if applicable. */
apply_errexit_errreturn(const command_T * c)501 void apply_errexit_errreturn(const command_T *c)
502 {
503 if (is_errexit_condition() && is_err_condition_for(c))
504 exit_shell_with_status(laststatus);
505 if (is_errreturn_condition() && is_err_condition_for(c))
506 exception = E_RETURN;
507 }
508
509 /* Returns true if the shell should exit because of the `errexit' option. */
is_errexit_condition(void)510 bool is_errexit_condition(void)
511 {
512 if (!shopt_errexit || suppresserrexit)
513 return false;
514 if (laststatus == Exit_SUCCESS)
515 return false;
516
517 #if YASH_ENABLE_LINEEDIT
518 if (le_state & LE_STATE_COMPLETING)
519 return false;
520 #endif
521
522 return true;
523 }
524
525 /* Returns true if the shell should return because of the `errreturn' option. */
is_errreturn_condition(void)526 bool is_errreturn_condition(void)
527 {
528 if (!shopt_errreturn || suppresserrreturn || execstate.noreturn)
529 return false;
530 return laststatus != Exit_SUCCESS;
531 }
532
533 /* Returns true if "errexit" and "errreturn" should be applied to the given
534 * command. */
is_err_condition_for(const command_T * c)535 bool is_err_condition_for(const command_T *c)
536 {
537 if (c == NULL)
538 return true;
539
540 /* If this is a multi-command pipeline, the commands are executed in
541 * subshells. Otherwise, we need to check the type of the command. */
542 if (c->next != NULL)
543 return true;
544
545 switch (c->c_type) {
546 case CT_SIMPLE:
547 case CT_SUBSHELL:
548 #if YASH_ENABLE_DOUBLE_BRACKET
549 case CT_BRACKET:
550 #endif
551 case CT_FUNCDEF:
552 return true;
553 case CT_GROUP:
554 case CT_IF:
555 case CT_FOR:
556 case CT_WHILE:
557 case CT_CASE:
558 return false;
559 }
560
561 assert(false);
562 }
563
564 /* Updates the contents of the `pipeinfo_T' to proceed to the next process
565 * execution. `pi->pi_fromprevfd' and `pi->pi_tonextfds[PIPE_OUT]' are closed,
566 * `pi->pi_tonextfds[PIPE_IN]' is moved to `pi->pi_fromprevfd', and,
567 * if `next' is true, a new pipe is opened in `pi->pi_tonextfds'; otherwise,
568 * `pi->pi_tonextfds' is assigned -1.
569 * Returns true iff successful. */
next_pipe(pipeinfo_T * pi,bool next)570 void next_pipe(pipeinfo_T *pi, bool next)
571 {
572 if (pi->pi_fromprevfd >= 0)
573 xclose(pi->pi_fromprevfd);
574 if (pi->pi_tonextfds[PIPE_OUT] >= 0)
575 xclose(pi->pi_tonextfds[PIPE_OUT]);
576 pi->pi_fromprevfd = pi->pi_tonextfds[PIPE_IN];
577 if (next) {
578 if (pipe(pi->pi_tonextfds) < 0)
579 goto fail;
580
581 /* The pipe's FDs must not be 0 or 1, or they may be overridden by each
582 * other when we move the pipe to the standard input/output later. So,
583 * if they are 0 or 1, we move them to bigger numbers. */
584 int origin = pi->pi_tonextfds[PIPE_IN];
585 int origout = pi->pi_tonextfds[PIPE_OUT];
586 if (origin < 2 || origout < 2) {
587 if (origin < 2)
588 pi->pi_tonextfds[PIPE_IN] = dup(origin);
589 if (origout < 2)
590 pi->pi_tonextfds[PIPE_OUT] = dup(origout);
591 if (origin < 2)
592 xclose(origin);
593 if (origout < 2)
594 xclose(origout);
595 if (pi->pi_tonextfds[PIPE_IN] < 0) {
596 xclose(pi->pi_tonextfds[PIPE_OUT]);
597 goto fail;
598 }
599 if (pi->pi_tonextfds[PIPE_OUT] < 0) {
600 xclose(pi->pi_tonextfds[PIPE_IN]);
601 goto fail;
602 }
603 }
604 } else {
605 pi->pi_tonextfds[PIPE_IN] = pi->pi_tonextfds[PIPE_OUT] = -1;
606 }
607 return;
608
609 fail:
610 pi->pi_tonextfds[PIPE_IN] = pi->pi_tonextfds[PIPE_OUT] = -1;
611 xerror(errno, Ngt("cannot open a pipe"));
612 }
613
614 /* Connects the pipe(s) and closes the pipes left. */
connect_pipes(pipeinfo_T * pi)615 void connect_pipes(pipeinfo_T *pi)
616 {
617 if (pi->pi_fromprevfd >= 0) {
618 xdup2(pi->pi_fromprevfd, STDIN_FILENO);
619 xclose(pi->pi_fromprevfd);
620 }
621 if (pi->pi_tonextfds[PIPE_OUT] >= 0) {
622 xdup2(pi->pi_tonextfds[PIPE_OUT], STDOUT_FILENO);
623 xclose(pi->pi_tonextfds[PIPE_OUT]);
624 }
625 if (pi->pi_tonextfds[PIPE_IN] >= 0)
626 xclose(pi->pi_tonextfds[PIPE_IN]);
627 }
628
629 /* Executes the command. */
exec_one_command(command_T * c,bool finally_exit)630 void exec_one_command(command_T *c, bool finally_exit)
631 {
632 /* prevent the command data from being freed in case the command is part of
633 * a function that is unset during execution. */
634 c = comsdup(c);
635
636 update_lineno(c->c_lineno);
637
638 if (c->c_type == CT_SIMPLE) {
639 exec_simple_command(c, finally_exit);
640 } else {
641 savefd_T *savefd;
642 if (open_redirections(c->c_redirs, &savefd)) {
643 exec_nonsimple_command(c, finally_exit && savefd == NULL);
644 undo_redirections(savefd);
645 } else {
646 undo_redirections(savefd);
647 laststatus = Exit_REDIRERR;
648 apply_errexit_errreturn(NULL);
649 }
650 }
651
652 comsfree(c);
653
654 if (finally_exit)
655 exit_shell();
656 }
657
658 /* Executes the simple command. */
exec_simple_command(const command_T * c,bool finally_exit)659 void exec_simple_command(const command_T *c, bool finally_exit)
660 {
661 lastcmdsubstatus = Exit_SUCCESS;
662
663 /* expand the command words */
664 int argc;
665 void **argv;
666 if (!expand_line(c->c_words, &argc, &argv)) {
667 laststatus = Exit_EXPERROR;
668 goto done;
669 }
670 if (is_interrupted())
671 goto done1;
672
673 /* execute the remaining part */
674 if (argc == 0)
675 finally_exit |= exec_simple_command_without_words(c);
676 else
677 finally_exit |=
678 exec_simple_command_with_words(c, argc, argv, finally_exit);
679
680 /* cleanup */
681 done1:
682 plfree(argv, free);
683 done:
684 if (finally_exit)
685 exit_shell();
686 }
687
688 /* Executes the simple command that has no expanded words.
689 * Returns true if the shell should exit. */
exec_simple_command_without_words(const command_T * c)690 bool exec_simple_command_without_words(const command_T *c)
691 {
692 /* perform assignments */
693 bool ok = do_assignments(c->c_assigns, false, shopt_allexport);
694 print_xtrace(NULL);
695 last_assign = c->c_assigns;
696 if (!ok) {
697 laststatus = Exit_ASSGNERR;
698 return !is_interactive_now;
699 }
700
701 /* done? */
702 if (c->c_redirs == NULL) {
703 laststatus = lastcmdsubstatus;
704 return false;
705 }
706
707 /* create a subshell to perform redirections in */
708 fork_and_wait_T faw = fork_and_wait(0);
709 if (faw.cpid != 0) {
710 /* parent process */
711 if (faw.namep != NULL)
712 *faw.namep = command_to_wcs(c, false);
713 return false;
714 }
715
716 /* open redirections in subshell */
717 savefd_T *savefd;
718 ok = open_redirections(c->c_redirs, &savefd);
719 undo_redirections(savefd);
720 exit_shell_with_status(ok ? lastcmdsubstatus : Exit_REDIRERR);
721 }
722
723 /* Executes the simple command that has one or more expanded words.
724 * `argv' must be a NULL-terminated array of pointers to wide strings that are
725 * the results of the word expansion on the simple command being executed.
726 * `argc' must be the number of words in `argv', which must be at least 1.
727 * If `finally_exit' is true, the shell process may be replaced by the command
728 * process. However, this function still may return in some cases.
729 * Returns true if the shell should exit. */
exec_simple_command_with_words(const command_T * c,int argc,void ** argv,bool finally_exit)730 bool exec_simple_command_with_words(
731 const command_T *c, int argc, void **argv, bool finally_exit)
732 {
733 assert(argc > 0);
734
735 char *argv0 = malloc_wcstombs(argv[0]);
736 if (argv0 == NULL)
737 argv0 = xstrdup("");
738
739 /* open redirections */
740 savefd_T *savefd;
741 if (!open_redirections(c->c_redirs, &savefd)) {
742 /* On redirection error, the command is not executed. */
743 laststatus = Exit_REDIRERR;
744 apply_errexit_errreturn(NULL);
745 if (posixly_correct && !is_interactive_now && is_special_builtin(argv0))
746 finally_exit = true;
747 goto done;
748 }
749
750 last_assign = c->c_assigns;
751
752 /* check if the command is a special built-in or function */
753 commandinfo_T cmdinfo;
754 search_command(argv0, argv[0], &cmdinfo, SCT_BUILTIN | SCT_FUNCTION);
755 special_builtin_executed = (cmdinfo.type == CT_SPECIALBUILTIN);
756
757 /* open a temporary variable environment */
758 bool temp = c->c_assigns != NULL && !special_builtin_executed;
759 if (temp)
760 open_new_environment(true);
761
762 /* perform the assignments */
763 if (!do_assignments(c->c_assigns, temp, true)) {
764 /* On assignment error, the command is not executed. */
765 print_xtrace(NULL);
766 laststatus = Exit_ASSGNERR;
767 if (!is_interactive_now)
768 finally_exit = true;
769 goto done1;
770 }
771 print_xtrace(argv);
772
773 /* find command path */
774 if (cmdinfo.type == CT_NONE) {
775 search_command(argv0, argv[0], &cmdinfo,
776 SCT_EXTERNAL | SCT_BUILTIN | SCT_CHECK);
777 if (cmdinfo.type == CT_NONE) {
778 if (!posixly_correct && command_not_found_handler(argv))
779 goto done1;
780 if (wcschr(argv[0], L'/') != NULL) {
781 cmdinfo.type = CT_EXTERNALPROGRAM;
782 cmdinfo.ci_path = argv0;
783 }
784 }
785 }
786
787 /* execute! */
788 wchar_t **namep = invoke_simple_command(&cmdinfo, argc, argv0, argv,
789 finally_exit && /* !temp && */ savefd == NULL);
790 if (namep != NULL)
791 *namep = command_to_wcs(c, false);
792
793 /* Redirections are not undone after a successful "exec" command:
794 * remove the saved data of file descriptors. */
795 if (exec_builtin_executed && laststatus == Exit_SUCCESS) {
796 clear_savefd(savefd);
797 savefd = NULL;
798 }
799 exec_builtin_executed = false;
800
801 /* cleanup */
802 done1:
803 if (temp)
804 close_current_environment();
805 done:
806 undo_redirections(savefd);
807 free(argv0);
808
809 return finally_exit;
810 }
811
812 /* Returns a pointer to the xtrace buffer.
813 * The buffer is initialized if not. */
get_xtrace_buffer(void)814 xwcsbuf_T *get_xtrace_buffer(void)
815 {
816 if (xtrace_buffer.contents == NULL)
817 wb_init(&xtrace_buffer);
818 return &xtrace_buffer;
819 }
820
821 /* Prints a trace if the "xtrace" option is on. */
print_xtrace(void * const * argv)822 void print_xtrace(void *const *argv)
823 {
824 bool tracevars = xtrace_buffer.contents != NULL
825 && xtrace_buffer.length > 0;
826
827 if (shopt_xtrace
828 && (!is_executing_auxiliary || shopt_traceall)
829 && (tracevars || argv != NULL)
830 #if YASH_ENABLE_LINEEDIT
831 && !(le_state & LE_STATE_ACTIVE)
832 #endif
833 ) {
834 bool first = true;
835
836 struct promptset_T prompt = get_prompt(4);
837 print_prompt(prompt.main);
838 print_prompt(prompt.styler);
839
840 if (tracevars) {
841 fprintf(stderr, "%ls", xtrace_buffer.contents + 1);
842 first = false;
843 }
844 if (argv != NULL) {
845 for (void *const *a = argv; *a != NULL; a++) {
846 if (!first)
847 fputc(' ', stderr);
848 first = false;
849
850 wchar_t *quoted = quote_as_word(*a);
851 fprintf(stderr, "%ls", quoted);
852 free(quoted);
853 }
854 }
855 fputc('\n', stderr);
856
857 print_prompt(PROMPT_RESET);
858 free_prompt(prompt);
859 }
860 if (xtrace_buffer.contents != NULL) {
861 wb_destroy(&xtrace_buffer);
862 xtrace_buffer.contents = NULL;
863 }
864 }
865
866 /* Searches for a command.
867 * The result is assigned to `*ci'.
868 * `name' and `wname' must contain the same string value.
869 * If the SCT_ALL flag is not set:
870 * * a function whose name contains a slash cannot be found
871 * * a regular built-in cannot be found in the POSIXly correct mode if the
872 * SCT_EXTERNAL flag is not set either.
873 * If the SCT_EXTERNAL flag is set, the SCT_CHECK flag is not set, and `name'
874 * contains a slash, the external command of the given `name' is always found.
875 */
search_command(const char * restrict name,const wchar_t * restrict wname,commandinfo_T * restrict ci,enum srchcmdtype_T type)876 void search_command(
877 const char *restrict name, const wchar_t *restrict wname,
878 commandinfo_T *restrict ci, enum srchcmdtype_T type)
879 {
880 bool slash = wcschr(wname, L'/') != NULL;
881
882 const builtin_T *bi;
883 if (!slash && (type & SCT_BUILTIN))
884 bi = get_builtin(name);
885 else
886 bi = NULL;
887 if (bi != NULL && bi->type == BI_SPECIAL) {
888 ci->type = CT_SPECIALBUILTIN;
889 ci->ci_builtin = bi->body;
890 return;
891 }
892
893 if ((type & SCT_FUNCTION) && (!slash || (type & SCT_ALL))) {
894 command_T *funcbody = get_function(wname);
895 if (funcbody != NULL) {
896 ci->type = CT_FUNCTION;
897 ci->ci_function = funcbody;
898 return;
899 }
900 }
901
902 if (bi != NULL) {
903 if (bi->type == BI_SEMISPECIAL) {
904 ci->type = CT_SEMISPECIALBUILTIN;
905 ci->ci_builtin = bi->body;
906 return;
907 } else if (!posixly_correct) {
908 goto regular_builtin;
909 }
910 }
911
912 if (slash) {
913 if (type & SCT_EXTERNAL) {
914 if (!(type & SCT_CHECK) || is_executable_regular(name)) {
915 ci->type = CT_EXTERNALPROGRAM;
916 ci->ci_path = name;
917 return;
918 }
919 }
920 } else {
921 if ((type & SCT_EXTERNAL) || (bi != NULL && (type & SCT_ALL))) {
922 const char *cmdpath;
923 if (type & SCT_STDPATH)
924 cmdpath = get_command_path_default(name);
925 else
926 cmdpath = get_command_path(name, false);
927 if (cmdpath != NULL) {
928 if (bi != NULL) {
929 regular_builtin:
930 assert(bi->type == BI_REGULAR);
931 ci->type = CT_REGULARBUILTIN;
932 ci->ci_builtin = bi->body;
933 } else {
934 ci->type = CT_EXTERNALPROGRAM;
935 ci->ci_path = cmdpath;
936 }
937 return;
938 }
939 }
940 }
941
942 /* command not found... */
943 ci->type = CT_NONE;
944 ci->ci_path = NULL;
945 return;
946 }
947
948 /* Returns true iff the specified command is a special built-in. */
is_special_builtin(const char * cmdname)949 bool is_special_builtin(const char *cmdname)
950 {
951 const builtin_T *bi = get_builtin(cmdname);
952 return bi != NULL && bi->type == BI_SPECIAL;
953 }
954
955 /* Executes $COMMAND_NOT_FOUND_HANDLER if any.
956 * `argv' is set to the positional parameters of the environment in which the
957 * handler is executed.
958 * Returns true iff the hander was executed and $HANDLED was set non-empty. */
command_not_found_handler(void * const * argv)959 bool command_not_found_handler(void *const *argv)
960 {
961 static bool handling = false;
962 if (handling)
963 return false; /* don't allow reentrance */
964 handling = true;
965
966 bool handled;
967 int result;
968
969 open_new_environment(false);
970 set_positional_parameters(argv);
971 set_variable(L VAR_HANDLED, xwcsdup(L""), SCOPE_LOCAL, false);
972
973 result = exec_variable_as_auxiliary_(VAR_COMMAND_NOT_FOUND_HANDLER);
974 if (result >= 0) {
975 const wchar_t *handledv = getvar(L VAR_HANDLED);
976 handled = (handledv != NULL && handledv[0] != L'\0');
977 } else {
978 handled = false;
979 }
980
981 close_current_environment();
982
983 handling = false;
984 if (handled) {
985 laststatus = result;
986 return true;
987 } else {
988 return false;
989 }
990 }
991
992 /* Invokes the simple command. */
993 /* `argv0' is the multibyte version of `argv[0]' */
invoke_simple_command(const commandinfo_T * ci,int argc,char * argv0,void ** argv,bool finally_exit)994 wchar_t **invoke_simple_command(
995 const commandinfo_T *ci, int argc, char *argv0, void **argv,
996 bool finally_exit)
997 {
998 assert(plcount(argv) == (size_t) argc);
999
1000 fork_and_wait_T faw = { 0, NULL };
1001
1002 switch (ci->type) {
1003 case CT_NONE:
1004 xerror(0, Ngt("no such command `%s'"), argv0);
1005 laststatus = Exit_NOTFOUND;
1006 break;
1007 case CT_EXTERNALPROGRAM:
1008 if (!finally_exit) {
1009 faw = fork_and_wait(t_leave);
1010 if (faw.cpid != 0)
1011 break;
1012 finally_exit = true;
1013 }
1014 exec_external_program(ci->ci_path, argc, argv0, argv, environ);
1015 break;
1016 case CT_SPECIALBUILTIN:
1017 case CT_SEMISPECIALBUILTIN:
1018 case CT_REGULARBUILTIN:
1019 yash_error_message_count = 0;
1020
1021 const wchar_t *savecbn = current_builtin_name;
1022 current_builtin_name = argv[0];
1023
1024 laststatus = ci->ci_builtin(argc, argv);
1025
1026 current_builtin_name = savecbn;
1027 break;
1028 case CT_FUNCTION:
1029 exec_function_body(ci->ci_function, &argv[1], finally_exit, false);
1030 break;
1031 }
1032 if (finally_exit)
1033 exit_shell();
1034 return faw.namep;
1035 }
1036
1037 /* Executes the external program.
1038 * path: path to the program to be executed
1039 * argc: number of strings in `argv'
1040 * argv0: multibyte version of `argv[0]'
1041 * argv: pointer to an array of pointers to wide strings that are passed to
1042 * the program */
exec_external_program(const char * path,int argc,char * argv0,void ** argv,char ** envs)1043 void exec_external_program(
1044 const char *path, int argc, char *argv0, void **argv, char **envs)
1045 {
1046 char *mbsargv[argc + 1];
1047 mbsargv[0] = argv0;
1048 for (int i = 1; i < argc; i++) {
1049 mbsargv[i] = malloc_wcstombs(argv[i]);
1050 if (mbsargv[i] == NULL)
1051 mbsargv[i] = xstrdup("");
1052 }
1053 mbsargv[argc] = NULL;
1054
1055 restore_signals(true);
1056
1057 xexecve(path, mbsargv, envs);
1058 int saveerrno = errno;
1059 if (saveerrno != ENOEXEC) {
1060 if (saveerrno == EACCES && is_directory(path))
1061 saveerrno = EISDIR;
1062 xerror(saveerrno,
1063 strcmp(mbsargv[0], path) == 0
1064 ? Ngt("cannot execute command `%s'")
1065 : Ngt("cannot execute command `%s' (%s)"),
1066 argv0, path);
1067 } else if (saveerrno != ENOENT) {
1068 exec_fall_back_on_sh(argc, mbsargv, envs, path);
1069 }
1070 laststatus = (saveerrno == ENOENT) ? Exit_NOTFOUND : Exit_NOEXEC;
1071
1072 set_signals();
1073
1074 for (int i = 1; i < argc; i++)
1075 free(mbsargv[i]);
1076 }
1077
1078 /* Calls `execve' until it doesn't return EINTR. */
xexecve(const char * path,char * const * argv,char * const * envp)1079 int xexecve(const char *path, char *const *argv, char *const *envp)
1080 {
1081 do
1082 execve(path, argv, envp);
1083 while (errno == EINTR);
1084 return -1;
1085 }
1086
1087 /* Executes the specified command as a shell script by `exec'ing a shell.
1088 * `path' is the full path to the script file.
1089 * Returns iff failed to `exec'. */
exec_fall_back_on_sh(int argc,char * const * argv,char * const * envp,const char * path)1090 void exec_fall_back_on_sh(
1091 int argc, char *const *argv, char *const *envp, const char *path)
1092 {
1093 assert(argv[argc] == NULL);
1094
1095 char *args[argc + 3];
1096 size_t index = 0;
1097 args[index++] = "sh";
1098 args[index++] = (char *) "-";
1099 if (strcmp(path, "--") == 0)
1100 args[index++] = "./--";
1101 else
1102 args[index++] = (char *) path;
1103 for (int i = 1; i < argc; i++)
1104 args[index++] = argv[i];
1105 args[index] = NULL;
1106 #if HAVE_PROC_SELF_EXE
1107 xexecve("/proc/self/exe", args, envp);
1108 #elif HAVE_PROC_CURPROC_FILE
1109 xexecve("/proc/curproc/file", args, envp);
1110 #elif HAVE_PROC_OBJECT_AOUT
1111 char *objpath = malloc_printf(
1112 "/proc/%jd/object/a.out", (intmax_t) getpid());
1113 xexecve(objpath, args, envp);
1114 free(objpath);
1115 #elif HAVE_PATHS_H && defined _PATH_BSHELL
1116 xexecve(_PATH_BSHELL, args, envp);
1117 #endif
1118 const char *shpath = get_command_path("sh", false);
1119 if (shpath != NULL)
1120 xexecve(shpath, args, envp);
1121 else
1122 errno = ENOENT;
1123 xerror(errno, Ngt("cannot invoke a new shell to execute script `%s'"),
1124 argv[0]);
1125 }
1126
1127 /* Executes the specified command as a function.
1128 * `args' are the arguments to the function, which are wide strings cast to
1129 * (void *).
1130 * If `complete' is true, `set_completion_variables' will be called after a new
1131 * variable environment was opened before the function body is executed. */
exec_function_body(command_T * body,void * const * args,bool finally_exit,bool complete)1132 void exec_function_body(
1133 command_T *body, void *const *args, bool finally_exit, bool complete)
1134 {
1135 execstate_T *saveexecstate = save_execstate();
1136 reset_execstate(false);
1137
1138 bool saveser = suppresserrreturn;
1139 suppresserrreturn = false;
1140
1141 open_new_environment(false);
1142 set_positional_parameters(args);
1143 #if YASH_ENABLE_LINEEDIT
1144 if (complete)
1145 set_completion_variables();
1146 #else
1147 (void) complete;
1148 #endif
1149 exec_commands(body, finally_exit ? E_SELF : E_NORMAL);
1150 close_current_environment();
1151
1152 cancel_return();
1153 suppresserrreturn = saveser;
1154 restore_execstate(saveexecstate);
1155 }
1156
1157 /* Executes the specified command whose type is not `CT_SIMPLE'.
1158 * The redirections for the command is not performed in this function. */
exec_nonsimple_command(command_T * c,bool finally_exit)1159 void exec_nonsimple_command(command_T *c, bool finally_exit)
1160 {
1161 switch (c->c_type) {
1162 case CT_SIMPLE:
1163 assert(false);
1164 case CT_SUBSHELL:
1165 if (finally_exit) {
1166 /* This is the last command to execute in the current shell, hence
1167 * no need to make a new child. */
1168 become_child(0);
1169 } else {
1170 /* make a child process to execute the command */
1171 fork_and_wait_T faw = fork_and_wait(0);
1172 if (faw.cpid != 0) {
1173 if (faw.namep != NULL)
1174 *faw.namep = command_to_wcs(c, false);
1175 break;
1176 }
1177 finally_exit = true;
1178 }
1179 // falls thru!
1180 case CT_GROUP:
1181 exec_and_or_lists(c->c_subcmds, finally_exit);
1182 break;
1183 case CT_IF:
1184 exec_if(c, finally_exit);
1185 break;
1186 case CT_FOR:
1187 exec_for(c, finally_exit);
1188 break;
1189 case CT_WHILE:
1190 exec_while(c, finally_exit);
1191 break;
1192 case CT_CASE:
1193 exec_case(c, finally_exit);
1194 break;
1195 #if YASH_ENABLE_DOUBLE_BRACKET
1196 case CT_BRACKET:
1197 laststatus = exec_double_bracket(c);
1198 if (finally_exit)
1199 exit_shell();
1200 break;
1201 #endif /* YASH_ENABLE_DOUBLE_BRACKET */
1202 case CT_FUNCDEF:
1203 exec_funcdef(c, finally_exit);
1204 break;
1205 }
1206 }
1207
1208 /* Executes the if command */
exec_if(const command_T * c,bool finally_exit)1209 void exec_if(const command_T *c, bool finally_exit)
1210 {
1211 assert(c->c_type == CT_IF);
1212
1213 for (const ifcommand_T *cmds = c->c_ifcmds;
1214 cmds != NULL;
1215 cmds = cmds->next) {
1216 if (need_break())
1217 goto done;
1218 if (exec_condition(cmds->ic_condition)) {
1219 exec_and_or_lists(cmds->ic_commands, finally_exit);
1220 assert(!finally_exit);
1221 return;
1222 }
1223 }
1224 laststatus = Exit_SUCCESS;
1225 done:
1226 if (finally_exit)
1227 exit_shell();
1228 }
1229
1230 /* Executes the condition of an if/while/until command. */
exec_condition(const and_or_T * c)1231 bool exec_condition(const and_or_T *c)
1232 {
1233 if (c == NULL)
1234 return true;
1235
1236 bool savesee = suppresserrexit, saveser = suppresserrreturn;
1237 suppresserrexit = suppresserrreturn = true;
1238 exec_and_or_lists(c, false);
1239 suppresserrexit = savesee, suppresserrreturn = saveser;
1240 return laststatus == Exit_SUCCESS;
1241 }
1242
1243 /* Executes the for command. */
exec_for(const command_T * c,bool finally_exit)1244 void exec_for(const command_T *c, bool finally_exit)
1245 {
1246 assert(c->c_type == CT_FOR);
1247 execstate.loopnest++;
1248 execstate.breakloopnest = execstate.loopnest;
1249
1250 int count;
1251 void **words;
1252
1253 if (c->c_forwords != NULL) {
1254 /* expand the words between "in" and "do" of the for command. */
1255 if (!expand_line(c->c_forwords, &count, &words)) {
1256 laststatus = Exit_EXPERROR;
1257 apply_errexit_errreturn(NULL);
1258 goto finish;
1259 }
1260 } else {
1261 /* no "in" keyword in the for command: use the positional parameters */
1262 struct get_variable_T v = get_variable(L"@");
1263 assert(v.type == GV_ARRAY && v.values != NULL);
1264 save_get_variable_values(&v);
1265 count = (int) v.count;
1266 words = v.values;
1267 }
1268
1269 #define CHECK_LOOP \
1270 if (execstate.breakloopnest < execstate.loopnest) { \
1271 goto done; \
1272 } else if (exception == E_CONTINUE) { \
1273 exception = E_NONE; \
1274 continue; \
1275 } else if (exception != E_NONE) { \
1276 goto done; \
1277 } else if (is_interrupted()) { \
1278 goto done; \
1279 } else (void) 0
1280
1281 int i;
1282 for (i = 0; i < count; i++) {
1283 if (!set_variable(c->c_forname, words[i],
1284 shopt_forlocal && !posixly_correct ?
1285 SCOPE_LOCAL : SCOPE_GLOBAL,
1286 false)) {
1287 laststatus = Exit_ASSGNERR;
1288 goto done;
1289 }
1290 exec_and_or_lists(c->c_forcmds, finally_exit && i + 1 == count);
1291
1292 if (c->c_forcmds == NULL)
1293 handle_signals();
1294 CHECK_LOOP;
1295 }
1296
1297 done:
1298 while (++i < count) /* free unused words */
1299 free(words[i]);
1300 free(words);
1301 if (count == 0 && c->c_forcmds != NULL)
1302 laststatus = Exit_SUCCESS;
1303 finish:
1304 execstate.loopnest--;
1305 if (finally_exit)
1306 exit_shell();
1307 }
1308
1309 /* Executes the while/until command. */
1310 /* The exit status of a while/until command is that of `c_whlcmds' executed
1311 * last. If `c_whlcmds' is not executed at all, the status is 0 regardless of
1312 * `c_whlcond'. */
exec_while(const command_T * c,bool finally_exit)1313 void exec_while(const command_T *c, bool finally_exit)
1314 {
1315 assert(c->c_type == CT_WHILE);
1316 execstate.loopnest++;
1317 execstate.breakloopnest = execstate.loopnest;
1318
1319 int status = Exit_SUCCESS;
1320 for (;;) {
1321 bool cond = exec_condition(c->c_whlcond);
1322
1323 if (c->c_whlcond == NULL)
1324 handle_signals();
1325 CHECK_LOOP;
1326
1327 if (cond != c->c_whltype)
1328 break;
1329 if (c->c_whlcmds != NULL) {
1330 exec_and_or_lists(c->c_whlcmds, false);
1331 status = laststatus;
1332 }
1333
1334 if (c->c_whlcmds == NULL)
1335 handle_signals();
1336 CHECK_LOOP;
1337 }
1338
1339 laststatus = status;
1340 done:
1341 execstate.loopnest--;
1342 if (finally_exit)
1343 exit_shell();
1344 }
1345 #undef CHECK_LOOP
1346
1347 /* Executes the case command. */
exec_case(const command_T * c,bool finally_exit)1348 void exec_case(const command_T *c, bool finally_exit)
1349 {
1350 assert(c->c_type == CT_CASE);
1351
1352 wchar_t *word = expand_single(c->c_casword, TT_SINGLE, Q_WORD, ES_NONE);
1353 if (word == NULL)
1354 goto fail;
1355
1356 for (const caseitem_T *ci = c->c_casitems; ci != NULL; ci = ci->next) {
1357 for (void **pats = ci->ci_patterns; *pats != NULL; pats++) {
1358 wchar_t *pattern =
1359 expand_single(*pats, TT_SINGLE, Q_WORD, ES_QUOTED);
1360 if (pattern == NULL)
1361 goto fail;
1362
1363 bool match = match_pattern(word, pattern);
1364 free(pattern);
1365 if (match) {
1366 if (ci->ci_commands != NULL) {
1367 exec_and_or_lists(ci->ci_commands, finally_exit);
1368 goto done;
1369 } else {
1370 goto success;
1371 }
1372 }
1373 }
1374 }
1375 success:
1376 laststatus = Exit_SUCCESS;
1377 done:
1378 free(word);
1379 if (finally_exit)
1380 exit_shell();
1381 return;
1382
1383 fail:
1384 laststatus = Exit_EXPERROR;
1385 apply_errexit_errreturn(NULL);
1386 goto done;
1387 }
1388
1389 /* Executes the function definition. */
exec_funcdef(const command_T * c,bool finally_exit)1390 void exec_funcdef(const command_T *c, bool finally_exit)
1391 {
1392 assert(c->c_type == CT_FUNCDEF);
1393
1394 wchar_t *funcname =
1395 expand_single(c->c_funcname, TT_SINGLE, Q_WORD, ES_NONE);
1396 if (funcname != NULL) {
1397 if (define_function(funcname, c->c_funcbody))
1398 laststatus = Exit_SUCCESS;
1399 else
1400 laststatus = Exit_ASSGNERR;
1401 free(funcname);
1402 } else {
1403 laststatus = Exit_EXPERROR;
1404 }
1405
1406 if (finally_exit)
1407 exit_shell();
1408 }
1409
1410 /* Forks a new child process and wait for it to finish.
1411 * `sigtype' is passed to `fork_and_reset'.
1412 * In the parent process, this function updates `laststatus' to the exit status
1413 * of the child.
1414 * In the child process, this function does not wait for anything.
1415 * Returns a pair of the return value of `fork' and a pointer to a pointer to
1416 * a wide string. If the pointer is non-null, the caller must assign it a
1417 * pointer to a newly malloced wide string that is the job name of the child. */
fork_and_wait(sigtype_T sigtype)1418 fork_and_wait_T fork_and_wait(sigtype_T sigtype)
1419 {
1420 fork_and_wait_T result;
1421 result.cpid = fork_and_reset(0, true, sigtype);
1422 if (result.cpid < 0) {
1423 /* Fork failed. */
1424 laststatus = Exit_NOEXEC;
1425 result.namep = NULL;
1426 } if (result.cpid > 0) {
1427 /* parent process */
1428 result.namep = wait_for_child(
1429 result.cpid,
1430 doing_job_control_now ? result.cpid : 0,
1431 doing_job_control_now);
1432 } else {
1433 /* child process */
1434 result.namep = NULL;
1435 }
1436 return result;
1437 }
1438
1439 /* Forks a subshell and does some settings.
1440 * If job control is active, the child process's process group ID is set to
1441 * `pgid'. If `pgid' is 0, the child process's process ID is used as the process
1442 * group ID..
1443 * If `pgid' is negative or job control is inactive, the process group ID is not
1444 * changed.
1445 * If job control is active and `fg' is true, the child process becomes a
1446 * foreground process.
1447 * `sigtype' specifies the settings of signals in the child.
1448 * `sigtype' is a bitwise OR of the followings:
1449 * t_quitint: SIGQUIT & SIGINT are ignored if the parent's job control is off
1450 * t_tstp: SIGTSTP is ignored if the parent is job-controlling
1451 * t_leave: Don't clear traps and shell FDs. Restore the signal mask for
1452 * SIGCHLD. Don't reset `execstate'. This option must be used iff the
1453 * shell is going to `exec' to an external program.
1454 * Returns the return value of `fork'. */
fork_and_reset(pid_t pgid,bool fg,sigtype_T sigtype)1455 pid_t fork_and_reset(pid_t pgid, bool fg, sigtype_T sigtype)
1456 {
1457 sigset_t savemask;
1458 if (sigtype & (t_quitint | t_tstp)) {
1459 /* block all signals to prevent the race condition */
1460 sigset_t all;
1461 sigfillset(&all);
1462 sigemptyset(&savemask);
1463 sigprocmask(SIG_BLOCK, &all, &savemask);
1464 }
1465
1466 pid_t cpid = fork();
1467
1468 if (cpid != 0) {
1469 if (cpid < 0) {
1470 /* fork failure */
1471 xerror(errno, Ngt("cannot make a child process"));
1472 } else {
1473 /* parent process */
1474 if (doing_job_control_now && pgid >= 0)
1475 setpgid(cpid, pgid);
1476 }
1477 if (sigtype & (t_quitint | t_tstp))
1478 sigprocmask(SIG_SETMASK, &savemask, NULL);
1479 } else {
1480 /* child process */
1481 if (doing_job_control_now && pgid >= 0) {
1482 setpgid(0, pgid);
1483 if (pgid == 0)
1484 pgid = getpgrp();
1485 shell_pgid = pgid;
1486 if (fg)
1487 put_foreground(pgid);
1488 }
1489 become_child(sigtype); /* signal mask is restored here */
1490 }
1491 return cpid;
1492 }
1493
1494 /* Resets traps, signal handlers, etc. for the current process to become a
1495 * subshell. See `fork_and_reset' for the meaning of the `sigtype' parameter. */
become_child(sigtype_T sigtype)1496 void become_child(sigtype_T sigtype)
1497 {
1498 if (sigtype & t_leave) {
1499 clear_exit_trap();
1500 } else {
1501 phantomize_traps();
1502 neglect_all_jobs();
1503 #if YASH_ENABLE_HISTORY
1504 close_history_file();
1505 #endif
1506 reset_execstate(true);
1507 }
1508
1509 if (sigtype & t_quitint)
1510 if (!doing_job_control_now)
1511 ignore_sigquit_and_sigint();
1512 if (sigtype & t_tstp)
1513 if (doing_job_control_now)
1514 ignore_sigtstp();
1515
1516 restore_signals(sigtype & t_leave); /* signal mask is restored here */
1517 clear_shellfds(sigtype & t_leave);
1518 is_interactive_now = false;
1519 suppresserrreturn = false;
1520 exitstatus = -1;
1521 }
1522
1523 /* Executes the command substitution and returns the string to substitute with.
1524 * This function blocks until the command finishes.
1525 * The return value is a newly-malloced string without a trailing newline.
1526 * NULL is returned on error. */
exec_command_substitution(const embedcmd_T * cmdsub)1527 wchar_t *exec_command_substitution(const embedcmd_T *cmdsub)
1528 {
1529 int pipefd[2];
1530 pid_t cpid;
1531
1532 if (cmdsub->is_preparsed
1533 ? cmdsub->value.preparsed == NULL
1534 : cmdsub->value.unparsed[0] == L'\0') /* empty command */
1535 return xwcsdup(L"");
1536
1537 /* open a pipe to receive output from the command */
1538 if (pipe(pipefd) < 0) {
1539 xerror(errno, Ngt("cannot open a pipe for the command substitution"));
1540 return NULL;
1541 }
1542
1543 /* If the child is stopped by SIGTSTP, it can never be resumed and
1544 * the shell will be stuck. So we specify the `t_tstp' flag to prevent the
1545 * child from being stopped by SIGTSTP. */
1546 cpid = fork_and_reset(-1, false, t_tstp);
1547 if (cpid < 0) {
1548 /* fork failure */
1549 xclose(pipefd[PIPE_IN]);
1550 xclose(pipefd[PIPE_OUT]);
1551 lastcmdsubstatus = Exit_NOEXEC;
1552 return NULL;
1553 } else if (cpid > 0) {
1554 /* parent process */
1555 FILE *f;
1556
1557 xclose(pipefd[PIPE_OUT]);
1558 f = fdopen(pipefd[PIPE_IN], "r");
1559 if (f == NULL) {
1560 xerror(errno,
1561 Ngt("cannot open a pipe for the command substitution"));
1562 xclose(pipefd[PIPE_IN]);
1563 lastcmdsubstatus = Exit_NOEXEC;
1564 return NULL;
1565 }
1566
1567 /* read output from the command */
1568 xwcsbuf_T buf;
1569 wint_t c;
1570 wb_init(&buf);
1571 while ((c = fgetwc(f)) != WEOF)
1572 wb_wccat(&buf, c);
1573 fclose(f);
1574
1575 /* wait for the child to finish */
1576 int savelaststatus = laststatus;
1577 wait_for_child(cpid, 0, false);
1578 lastcmdsubstatus = laststatus;
1579 laststatus = savelaststatus;
1580
1581 /* trim trailing newlines and return */
1582 size_t len = buf.length;
1583 while (len > 0 && buf.contents[len - 1] == L'\n')
1584 len--;
1585 return wb_towcs(wb_truncate(&buf, len));
1586 } else {
1587 /* child process */
1588 xclose(pipefd[PIPE_IN]);
1589 if (pipefd[PIPE_OUT] != STDOUT_FILENO) { /* connect the pipe */
1590 if (xdup2(pipefd[PIPE_OUT], STDOUT_FILENO) < 0)
1591 exit(Exit_NOEXEC);
1592 xclose(pipefd[PIPE_OUT]);
1593 }
1594
1595 if (cmdsub->is_preparsed)
1596 exec_and_or_lists(cmdsub->value.preparsed, true);
1597 else
1598 exec_wcs(cmdsub->value.unparsed, gt("command substitution"), true);
1599 assert(false);
1600 }
1601 }
1602
1603 /* Executes the value of the specified variable.
1604 * The variable value is parsed as commands.
1605 * If the `varname' names an array, every element of the array is executed (but
1606 * if the iteration is interrupted by the "break -i" command, the remaining
1607 * elements are not executed).
1608 * `codename' is passed to `exec_wcs' as the command name.
1609 * Returns the exit status of the executed command (or zero if none executed, or
1610 * -1 if the variable is unset).
1611 * When this function returns, `laststatus' is restored to the original value.*/
exec_variable_as_commands(const wchar_t * varname,const char * codename)1612 int exec_variable_as_commands(const wchar_t *varname, const char *codename)
1613 {
1614 struct get_variable_T gv = get_variable(varname);
1615
1616 switch (gv.type) {
1617 case GV_NOTFOUND:
1618 return -1;
1619 case GV_SCALAR:
1620 case GV_ARRAY:
1621 break;
1622 case GV_ARRAY_CONCAT:
1623 /* should execute the concatenated value, but is not supported now*/
1624 return -1;
1625 }
1626
1627 /* copy the array values in case they are unset during execution */
1628 save_get_variable_values(&gv);
1629
1630 /* prevent "break" and "continue" */
1631 execstate_T *saveexecstate = save_execstate();
1632 // reset_execstate(false); /* don't reset `execstate.noreturn' */
1633 execstate.loopnest = 0;
1634
1635 int result = exec_iteration(gv.values, codename);
1636
1637 restore_execstate(saveexecstate);
1638
1639 plfree(gv.values, free);
1640 return result;
1641 }
1642
1643 /* Executes commands in the given array of wide strings (iterative execution).
1644 * The strings are parsed and executed one by one.
1645 * If the iteration is interrupted by the "break -i" command, the remaining
1646 * elements are not executed.
1647 * `codename' is passed to `exec_wcs' as the command name.
1648 * Returns the exit status of the executed command (or zero if none executed).
1649 * When this function returns, `laststatus' is restored to the original value.*/
exec_iteration(void * const * commands,const char * codename)1650 int exec_iteration(void *const *commands, const char *codename)
1651 {
1652 int savelaststatus = laststatus, commandstatus = Exit_SUCCESS;
1653 bool saveiterating = execstate.iterating;
1654 execstate.iterating = true;
1655
1656 for (void *const *command = commands; *command != NULL; command++) {
1657 exec_wcs(*command, codename, false);
1658 commandstatus = laststatus;
1659 laststatus = savelaststatus;
1660 switch (exception) {
1661 case E_BREAK_ITERATION:
1662 exception = E_NONE;
1663 /* falls thru! */
1664 default:
1665 goto done;
1666 case E_CONTINUE_ITERATION:
1667 exception = E_NONE;
1668 /* falls thru! */
1669 case E_NONE:
1670 break;
1671 }
1672 if (execstate.breakloopnest < execstate.loopnest || is_interrupted())
1673 goto done;
1674 }
1675 done:
1676 execstate.iterating = saveiterating;
1677 return commandstatus;
1678 }
1679
1680 /* Calls `exec_variable_as_commands' with `is_executing_auxiliary' set to true.
1681 */
exec_variable_as_auxiliary(const wchar_t * varname,const char * codename)1682 int exec_variable_as_auxiliary(const wchar_t *varname, const char *codename)
1683 {
1684 bool save_executing_auxiliary = is_executing_auxiliary;
1685 is_executing_auxiliary = true;
1686 int result = exec_variable_as_commands(varname, codename);
1687 is_executing_auxiliary = save_executing_auxiliary;
1688 return result;
1689 }
1690
1691 #if YASH_ENABLE_LINEEDIT
1692
1693 /* Autoloads the specified file to load a completion function definition.
1694 * String `cmdname', which may be NULL, is used as the only positional parameter
1695 * during script execution.
1696 * Returns true iff a file was autoloaded. */
autoload_completion_function_file(const wchar_t * filename,const wchar_t * cmdname)1697 bool autoload_completion_function_file(
1698 const wchar_t *filename, const wchar_t *cmdname)
1699 {
1700 char *mbsfilename = malloc_wcstombs(filename);
1701 if (mbsfilename == NULL)
1702 return false;
1703
1704 char *path = which(mbsfilename, get_path_array(PA_LOADPATH),
1705 is_readable_regular);
1706 if (path == NULL) {
1707 le_compdebug("file \"%s\" was not found in $YASH_LOADPATH",
1708 mbsfilename);
1709 free(mbsfilename);
1710 return false;
1711 }
1712
1713 int fd = move_to_shellfd(open(path, O_RDONLY));
1714 if (fd < 0) {
1715 le_compdebug("cannot open file \"%s\"", path);
1716 free(path);
1717 return false;
1718 }
1719
1720 execstate_T *saveexecstate = save_execstate();
1721 int savelaststatus = laststatus;
1722 bool saveposix = posixly_correct;
1723 reset_execstate(true);
1724 posixly_correct = false;
1725 open_new_environment(false);
1726 set_positional_parameters((void *[]) { (void *) cmdname, NULL });
1727
1728 le_compdebug("executing file \"%s\" (autoload)", path);
1729 exec_input(fd, mbsfilename, 0);
1730 le_compdebug("finished executing file \"%s\"", path);
1731
1732 close_current_environment();
1733 posixly_correct = saveposix;
1734 laststatus = savelaststatus;
1735 cancel_return();
1736 restore_execstate(saveexecstate);
1737 remove_shellfd(fd);
1738 xclose(fd);
1739 free(path);
1740 free(mbsfilename);
1741 return true;
1742 }
1743
1744 /* Calls the function whose name is `funcname' as a completion function.
1745 * Returns false if no such function has been defined. */
call_completion_function(const wchar_t * funcname)1746 bool call_completion_function(const wchar_t *funcname)
1747 {
1748 command_T *func = get_function(funcname);
1749 if (func == NULL) {
1750 le_compdebug("completion function \"%ls\" is not defined", funcname);
1751 return false;
1752 }
1753
1754 execstate_T *saveexecstate = save_execstate();
1755 int savelaststatus = laststatus;
1756 bool saveposix = posixly_correct, saveerrreturn = shopt_errreturn;
1757 reset_execstate(true);
1758 posixly_correct = false, shopt_errreturn = false;
1759
1760 le_compdebug("executing completion function \"%ls\"", funcname);
1761
1762 exec_function_body(func, (void *[]) { NULL }, false, true);
1763
1764 le_compdebug("finished executing completion function \"%ls\"", funcname);
1765 le_compdebug(" with the exit status of %d", laststatus);
1766
1767 posixly_correct = saveposix, shopt_errreturn = saveerrreturn;
1768 laststatus = savelaststatus;
1769 cancel_return();
1770 restore_execstate(saveexecstate);
1771
1772 return true;
1773 }
1774
1775 #endif /* YASH_ENABLE_LINEEDIT */
1776
1777
1778 /********** Built-ins **********/
1779
1780 static int exec_builtin_2(int argc, void **argv, const wchar_t *as, bool clear)
1781 __attribute__((nonnull(2)));
1782 static int command_builtin_execute(
1783 int argc, void **argv, enum srchcmdtype_T type)
1784 __attribute__((nonnull));
1785 static bool print_command_info(const wchar_t *commandname,
1786 enum srchcmdtype_T type, bool alias, bool keyword, bool humanfriendly)
1787 __attribute__((nonnull));
1788 static void print_command_absolute_path(
1789 const char *name, const char *path, bool humanfriendly)
1790 __attribute__((nonnull));
1791 static void print_command_path(
1792 const char *name, const char *path, bool humanfriendly)
1793 __attribute__((nonnull));
1794
1795 /* Options for the "break", "continue" and "eval" built-ins. */
1796 const struct xgetopt_T iter_options[] = {
1797 { L'i', L"iteration", OPTARG_NONE, false, NULL, },
1798 #if YASH_ENABLE_HELP
1799 { L'-', L"help", OPTARG_NONE, false, NULL, },
1800 #endif
1801 { L'\0', NULL, 0, false, NULL, },
1802 };
1803
1804 /* Options for the "return" built-in. */
1805 const struct xgetopt_T return_options[] = {
1806 { L'n', L"no-return", OPTARG_NONE, false, NULL, },
1807 #if YASH_ENABLE_HELP
1808 { L'-', L"help", OPTARG_NONE, false, NULL, },
1809 #endif
1810 { L'\0', NULL, 0, false, NULL, },
1811 };
1812
1813 /* The "return" built-in, which accepts the following option:
1814 * -n: don't return from a function. */
return_builtin(int argc,void ** argv)1815 int return_builtin(int argc, void **argv)
1816 {
1817 bool noreturn = false;
1818
1819 const struct xgetopt_T *opt;
1820 xoptind = 0;
1821 while ((opt = xgetopt(argv, return_options, 0)) != NULL) {
1822 switch (opt->shortopt) {
1823 case L'n':
1824 noreturn = true;
1825 break;
1826 #if YASH_ENABLE_HELP
1827 case L'-':
1828 return print_builtin_help(ARGV(0));
1829 #endif
1830 default:
1831 return special_builtin_error(Exit_ERROR);
1832 }
1833 }
1834
1835 if (!validate_operand_count(argc - xoptind, 0, 1))
1836 return special_builtin_error(Exit_ERROR);
1837
1838 int status;
1839 const wchar_t *statusstr = ARGV(xoptind);
1840 if (statusstr != NULL) {
1841 if (!xwcstoi(statusstr, 10, &status) || status < 0) {
1842 xerror(0, Ngt("`%ls' is not a valid integer"), statusstr);
1843 status = Exit_ERROR;
1844 special_builtin_error(status);
1845 /* return anyway */
1846 }
1847 } else {
1848 status = (savelaststatus >= 0) ? savelaststatus : laststatus;
1849 }
1850 if (!noreturn) {
1851 if (execstate.noreturn && is_interactive_now) {
1852 xerror(0, Ngt("cannot be used in the interactive mode"));
1853 return Exit_FAILURE;
1854 }
1855 exception = E_RETURN;
1856 }
1857 return status;
1858 }
1859
1860 #if YASH_ENABLE_HELP
1861 const char return_help[] = Ngt(
1862 "return from a function or script"
1863 );
1864 const char return_syntax[] = Ngt(
1865 "\treturn [-n] [exit_status]\n"
1866 );
1867 #endif
1868
1869 /* The "break"/"continue" built-in, which accepts the following option:
1870 * -i: iterative execution */
break_builtin(int argc,void ** argv)1871 int break_builtin(int argc, void **argv)
1872 {
1873 bool iter = false;
1874
1875 const struct xgetopt_T *opt;
1876 xoptind = 0;
1877 while ((opt = xgetopt(argv, iter_options, 0)) != NULL) {
1878 switch (opt->shortopt) {
1879 case L'i':
1880 iter = true;
1881 break;
1882 #if YASH_ENABLE_HELP
1883 case L'-':
1884 return print_builtin_help(ARGV(0));
1885 #endif
1886 default:
1887 return special_builtin_error(Exit_ERROR);
1888 }
1889 }
1890
1891 if (!validate_operand_count(argc - xoptind, 0, iter ? 0 : 1))
1892 return special_builtin_error(Exit_ERROR);
1893
1894 if (iter) {
1895 /* break/continue iteration */
1896 if (!execstate.iterating) {
1897 xerror(0, Ngt("not in an iteration"));
1898 return Exit_ERROR;
1899 }
1900 if (wcscmp(ARGV(0), L"break") == 0) {
1901 exception = E_BREAK_ITERATION;
1902 } else {
1903 assert(wcscmp(ARGV(0), L"continue") == 0);
1904 exception = E_CONTINUE_ITERATION;
1905 }
1906 return laststatus;
1907 } else {
1908 unsigned count;
1909 const wchar_t *countstr = ARGV(xoptind);
1910 if (countstr == NULL) {
1911 count = 1;
1912 } else {
1913 unsigned long countl;
1914 if (!xwcstoul(countstr, 0, &countl)) {
1915 xerror(0, Ngt("`%ls' is not a valid integer"), countstr);
1916 return special_builtin_error(Exit_ERROR);
1917 } else if (countl == 0) {
1918 xerror(0, Ngt("%u is not a positive integer"), 0u);
1919 return special_builtin_error(Exit_ERROR);
1920 } else if (countl > UINT_MAX) {
1921 count = UINT_MAX;
1922 } else {
1923 count = (unsigned) countl;
1924 }
1925 }
1926 assert(count > 0);
1927 if (execstate.loopnest == 0) {
1928 xerror(0, Ngt("not in a loop"));
1929 return special_builtin_error(Exit_ERROR);
1930 }
1931 if (count > execstate.loopnest)
1932 count = execstate.loopnest;
1933 if (wcscmp(ARGV(0), L"break") == 0) {
1934 execstate.breakloopnest = execstate.loopnest - count;
1935 } else {
1936 assert(wcscmp(ARGV(0), L"continue") == 0);
1937 execstate.breakloopnest = execstate.loopnest - count + 1;
1938 exception = E_CONTINUE;
1939 }
1940 return Exit_SUCCESS;
1941 }
1942 }
1943
1944 #if YASH_ENABLE_HELP
1945
1946 const char break_help[] = Ngt(
1947 "exit a loop"
1948 );
1949 const char break_syntax[] = Ngt(
1950 "\tbreak [count]\n"
1951 "\tbreak -i\n"
1952 );
1953
1954 const char continue_help[] = Ngt(
1955 "continue a loop"
1956 );
1957 const char continue_syntax[] = Ngt(
1958 "\tcontinue [count]\n"
1959 "\tcontinue -i\n"
1960 );
1961
1962 #endif
1963
1964 /* The "eval" built-in, which accepts the following option:
1965 * -i: iterative execution */
eval_builtin(int argc,void ** argv)1966 int eval_builtin(int argc __attribute__((unused)), void **argv)
1967 {
1968 bool iter = false;
1969
1970 const struct xgetopt_T *opt;
1971 xoptind = 0;
1972 while ((opt = xgetopt(argv, iter_options, XGETOPT_POSIX)) != NULL) {
1973 switch (opt->shortopt) {
1974 case L'i':
1975 iter = true;
1976 break;
1977 #if YASH_ENABLE_HELP
1978 case L'-':
1979 return print_builtin_help(ARGV(0));
1980 #endif
1981 default:
1982 return special_builtin_error(Exit_ERROR);
1983 }
1984 }
1985
1986 if (iter) {
1987 return exec_iteration(&argv[xoptind], "eval");
1988 } else {
1989 wchar_t *args = joinwcsarray(&argv[xoptind], L" ");
1990 exec_wcs(args, "eval", false);
1991 free(args);
1992 return laststatus;
1993 }
1994 }
1995
1996 #if YASH_ENABLE_HELP
1997 const char eval_help[] = Ngt(
1998 "evaluate arguments as a command"
1999 );
2000 const char eval_syntax[] = Ngt(
2001 "\teval [-i] [argument...]\n"
2002 );
2003 #endif
2004
2005 /* Options for the "." built-in. */
2006 const struct xgetopt_T dot_options[] = {
2007 { L'A', L"no-alias", OPTARG_NONE, false, NULL, },
2008 { L'L', L"autoload", OPTARG_NONE, false, NULL, },
2009 #if YASH_ENABLE_HELP
2010 { L'-', L"help", OPTARG_NONE, false, NULL, },
2011 #endif
2012 { L'\0', NULL, 0, false, NULL, },
2013 };
2014
2015 /* The "." built-in, which accepts the following option:
2016 * -A: disable aliases
2017 * -L: autoload */
dot_builtin(int argc,void ** argv)2018 int dot_builtin(int argc, void **argv)
2019 {
2020 bool enable_alias = true, autoload = false;
2021
2022 const struct xgetopt_T *opt;
2023 xoptind = 0;
2024 while ((opt = xgetopt(argv, dot_options, XGETOPT_POSIX)) != NULL) {
2025 switch (opt->shortopt) {
2026 case L'A':
2027 enable_alias = false;
2028 break;
2029 case L'L':
2030 autoload = true;
2031 break;
2032 #if YASH_ENABLE_HELP
2033 case L'-':
2034 return print_builtin_help(ARGV(0));
2035 #endif
2036 default:
2037 return special_builtin_error(Exit_ERROR);
2038 }
2039 }
2040
2041 const wchar_t *filename = ARGV(xoptind++);
2042 if (filename == NULL)
2043 return special_builtin_error(insufficient_operands_error(1));
2044
2045 bool has_args = xoptind < argc;
2046 if (has_args && posixly_correct)
2047 return special_builtin_error(too_many_operands_error(1));
2048
2049 char *mbsfilename = malloc_wcstombs(filename);
2050 if (mbsfilename == NULL) {
2051 xerror(EILSEQ, Ngt("unexpected error"));
2052 return Exit_ERROR;
2053 }
2054
2055 char *path;
2056 if (autoload) {
2057 path = which(mbsfilename, get_path_array(PA_LOADPATH),
2058 is_readable_regular);
2059 if (path == NULL) {
2060 xerror(0, Ngt("file `%s' was not found in $YASH_LOADPATH"),
2061 mbsfilename);
2062 goto error;
2063 }
2064 } else if (wcschr(filename, L'/') == NULL) {
2065 path = which(mbsfilename, get_path_array(PA_PATH), is_readable_regular);
2066 if (path == NULL) {
2067 if (!posixly_correct) {
2068 path = mbsfilename;
2069 } else {
2070 xerror(0, Ngt("file `%s' was not found in $PATH"), mbsfilename);
2071 goto error;
2072 }
2073 }
2074 } else {
2075 path = mbsfilename;
2076 }
2077
2078 int fd = move_to_shellfd(open(path, O_RDONLY));
2079 if (path != mbsfilename)
2080 free(path);
2081 if (fd < 0) {
2082 xerror(errno, Ngt("cannot open file `%s'"), mbsfilename);
2083 goto error;
2084 }
2085
2086 if (has_args) {
2087 open_new_environment(false);
2088 set_positional_parameters(&argv[xoptind]);
2089 }
2090
2091 execstate_T *saveexecstate = save_execstate();
2092 reset_execstate(false);
2093
2094 bool saveser = suppresserrreturn;
2095 suppresserrreturn = false;
2096
2097 exec_input(fd, mbsfilename, enable_alias ? XIO_SUBST_ALIAS : 0);
2098
2099 cancel_return();
2100 suppresserrreturn = saveser;
2101 restore_execstate(saveexecstate);
2102 remove_shellfd(fd);
2103 xclose(fd);
2104 free(mbsfilename);
2105
2106 if (has_args) {
2107 close_current_environment();
2108 }
2109
2110 return laststatus;
2111
2112 error:
2113 free(mbsfilename);
2114 if (special_builtin_executed && !is_interactive_now)
2115 exit_shell_with_status(Exit_FAILURE);
2116 return Exit_FAILURE;
2117 }
2118
2119 #if YASH_ENABLE_HELP
2120 const char dot_help[] = Ngt(
2121 "read a file and execute commands"
2122 );
2123 const char dot_syntax[] = Ngt(
2124 "\t. [-AL] file [argument...]\n"
2125 );
2126 #endif
2127
2128 /* Options for the "exec" built-in. */
2129 const struct xgetopt_T exec_options[] = {
2130 { L'a', L"as", OPTARG_REQUIRED, false, NULL, },
2131 { L'c', L"clear", OPTARG_NONE, false, NULL, },
2132 { L'f', L"force", OPTARG_NONE, false, NULL, },
2133 #if YASH_ENABLE_HELP
2134 { L'-', L"help", OPTARG_NONE, false, NULL, },
2135 #endif
2136 { L'\0', NULL, 0, false, NULL, },
2137 };
2138
2139 /* The "exec" built-in, which accepts the following options:
2140 * -a name: give <name> as argv[0] to the command
2141 * -c: don't pass environment variables to the command
2142 * -f: suppress error when we have stopped jobs */
exec_builtin(int argc,void ** argv)2143 int exec_builtin(int argc, void **argv)
2144 {
2145 const wchar_t *as = NULL;
2146 bool clear = false, force = false;
2147
2148 const struct xgetopt_T *opt;
2149 xoptind = 0;
2150 while ((opt = xgetopt(argv, exec_options, XGETOPT_POSIX)) != NULL) {
2151 switch (opt->shortopt) {
2152 case L'a': as = xoptarg; break;
2153 case L'c': clear = true; break;
2154 case L'f': force = true; break;
2155 #if YASH_ENABLE_HELP
2156 case L'-':
2157 return print_builtin_help(ARGV(0));
2158 #endif
2159 default:
2160 return special_builtin_error(Exit_ERROR);
2161 }
2162 }
2163
2164 exec_builtin_executed = true;
2165
2166 if (xoptind == argc)
2167 return Exit_SUCCESS;
2168 if (!posixly_correct && is_interactive_now && !force) {
2169 size_t sjc = stopped_job_count();
2170 if (sjc > 0) {
2171 fprintf(stderr,
2172 ngt("You have a stopped job!",
2173 "You have %zu stopped jobs!",
2174 sjc),
2175 sjc);
2176 fprintf(stderr, gt(" Use the -f option to exec anyway.\n"));
2177 return Exit_FAILURE;
2178 }
2179 }
2180
2181 return exec_builtin_2(argc - xoptind, &argv[xoptind], as, clear);
2182 }
2183
2184 /* The main part of the "exec" built-in.
2185 * argc, argv: the operands (not arguments) of the "exec" built-in.
2186 * as: value of the -a option or NULL
2187 * clear: true iff the -c option is specified */
exec_builtin_2(int argc,void ** argv,const wchar_t * as,bool clear)2188 int exec_builtin_2(int argc, void **argv, const wchar_t *as, bool clear)
2189 {
2190 int err;
2191
2192 const wchar_t *saveargv0 = ARGV(0);
2193 char *mbssaveargv0 = malloc_wcstombs(saveargv0);
2194 if (mbssaveargv0 == NULL) {
2195 xerror(EILSEQ, Ngt("unexpected error"));
2196 err = Exit_NOEXEC;
2197 goto error1;
2198 }
2199
2200 char *mbsargv0;
2201 if (as != NULL) {
2202 mbsargv0 = malloc_wcstombs(as);
2203 if (mbsargv0 == NULL) {
2204 xerror(EILSEQ, Ngt("unexpected error"));
2205 err = Exit_NOEXEC;
2206 goto error2;
2207 }
2208 argv[0] = (void *) as;
2209 } else {
2210 mbsargv0 = mbssaveargv0;
2211 }
2212
2213 const char *commandpath;
2214 if (wcschr(saveargv0, L'/') != NULL) {
2215 commandpath = mbssaveargv0;
2216 } else {
2217 commandpath = get_command_path(mbssaveargv0, false);
2218 if (commandpath == NULL) {
2219 xerror(0, Ngt("no such command `%s'"), mbssaveargv0);
2220 err = Exit_NOTFOUND;
2221 goto error3;
2222 }
2223 }
2224
2225 char **envs;
2226 if (clear) {
2227 /* use the environment that contains only the variables assigned by the
2228 * assignment for this `exec' built-in. */
2229 plist_T list;
2230
2231 pl_init(&list);
2232 for (const assign_T *assign = last_assign;
2233 assign != NULL;
2234 assign = assign->next) {
2235 char *value = get_exported_value(assign->a_name);
2236 if (value != NULL) {
2237 pl_add(&list, malloc_printf("%ls=%s", assign->a_name, value));
2238 free(value);
2239 }
2240 }
2241 envs = (char **) pl_toary(&list);
2242 } else {
2243 envs = environ;
2244 }
2245
2246 exec_external_program(commandpath, argc, mbsargv0, argv, envs);
2247 err = laststatus;
2248
2249 if (clear)
2250 plfree((void **) envs, free);
2251 error3:
2252 if (as != NULL) {
2253 free(mbsargv0);
2254 argv[0] = (void *) saveargv0;
2255 }
2256 error2:
2257 free(mbssaveargv0);
2258 error1:
2259 if (posixly_correct || !is_interactive_now)
2260 exit(err);
2261 return err;
2262 }
2263
2264 #if YASH_ENABLE_HELP
2265 const char exec_help[] = Ngt(
2266 "replace the shell process with an external command"
2267 );
2268 const char exec_syntax[] = Ngt(
2269 "\texec [-cf] [-a name] [command [argument...]]\n"
2270 );
2271 #endif
2272
2273 /* Options for the "command" built-in. */
2274 const struct xgetopt_T command_options[] = {
2275 { L'a', L"alias", OPTARG_NONE, false, NULL, },
2276 { L'b', L"builtin-command", OPTARG_NONE, false, NULL, },
2277 { L'e', L"external-command", OPTARG_NONE, false, NULL, },
2278 { L'f', L"function", OPTARG_NONE, false, NULL, },
2279 { L'k', L"keyword", OPTARG_NONE, false, NULL, },
2280 { L'p', L"standard-path", OPTARG_NONE, true, NULL, },
2281 { L'v', L"identify", OPTARG_NONE, true, NULL, },
2282 { L'V', L"verbose-identify", OPTARG_NONE, true, NULL, },
2283 #if YASH_ENABLE_HELP
2284 { L'-', L"help", OPTARG_NONE, false, NULL, },
2285 #endif
2286 { L'\0', NULL, 0, false, NULL, },
2287 };
2288
2289 /* The "command"/"type" built-in, which accepts the following options:
2290 * -a: search aliases
2291 * -b: search built-ins
2292 * -e: search external commands
2293 * -f: search functions
2294 * -k: search keywords
2295 * -p: use the default path to find the command
2296 * -v: print info about the command
2297 * -V: print info about the command in a human-friendly format */
command_builtin(int argc,void ** argv)2298 int command_builtin(int argc, void **argv)
2299 {
2300 bool argv0istype = wcscmp(ARGV(0), L"type") == 0;
2301 bool printinfo = argv0istype, humanfriendly = argv0istype;
2302 enum srchcmdtype_T type = 0;
2303 bool aliases = false, keywords = false, defpath = false;
2304
2305 const struct xgetopt_T *opt;
2306 xoptind = 0;
2307 while ((opt = xgetopt(argv, command_options, XGETOPT_POSIX)) != NULL) {
2308 switch (opt->shortopt) {
2309 case L'a': aliases = true; break;
2310 case L'b': type |= SCT_BUILTIN; break;
2311 case L'e': type |= SCT_EXTERNAL; break;
2312 case L'f': type |= SCT_FUNCTION; break;
2313 case L'k': keywords = true; break;
2314 case L'p': defpath = true; break;
2315 case L'v': printinfo = true; humanfriendly = false; break;
2316 case L'V': printinfo = true; humanfriendly = true; break;
2317 #if YASH_ENABLE_HELP
2318 case L'-':
2319 return print_builtin_help(ARGV(0));
2320 #endif
2321 default:
2322 return Exit_ERROR;
2323 }
2324 }
2325
2326 if (!printinfo) {
2327 if (aliases || keywords) {
2328 xerror(0,
2329 Ngt("the -a or -k option must be used with the -v option"));
2330 return Exit_ERROR;
2331 }
2332
2333 if (xoptind == argc) {
2334 if (posixly_correct)
2335 return insufficient_operands_error(1);
2336 else
2337 return Exit_SUCCESS;
2338 }
2339
2340 if (type == 0)
2341 type = SCT_EXTERNAL | SCT_BUILTIN;
2342 else
2343 type |= SCT_ALL;
2344 if (defpath)
2345 type |= SCT_STDPATH;
2346 return command_builtin_execute(
2347 argc - xoptind, &argv[xoptind], type);
2348 } else {
2349 if (posixly_correct && !validate_operand_count(argc - xoptind, 1,
2350 argv0istype ? SIZE_MAX : 1))
2351 return Exit_ERROR;
2352
2353 if (type == 0 && !aliases && !keywords) {
2354 type = SCT_EXTERNAL | SCT_BUILTIN | SCT_FUNCTION;
2355 aliases = keywords = true;
2356 } else {
2357 type |= SCT_ALL;
2358 }
2359 if (defpath)
2360 type |= SCT_STDPATH;
2361 type |= SCT_CHECK;
2362
2363 bool ok = true;
2364 clearerr(stdout);
2365 for (int i = xoptind; i < argc; i++) {
2366 ok &= print_command_info(
2367 ARGV(i), type, aliases, keywords, humanfriendly);
2368 if (ferror(stdout))
2369 break;
2370 }
2371 return ok && yash_error_message_count == 0
2372 ? Exit_SUCCESS : Exit_FAILURE;
2373 }
2374 }
2375
2376 /* Executes the specified simple command.
2377 * `argc' must be positive.
2378 * Returns the exit status of the command. */
command_builtin_execute(int argc,void ** argv,enum srchcmdtype_T type)2379 int command_builtin_execute(int argc, void **argv, enum srchcmdtype_T type)
2380 {
2381 char *argv0 = malloc_wcstombs(argv[0]);
2382 commandinfo_T ci;
2383
2384 if (argv0 == NULL) {
2385 xerror(EILSEQ, NULL);
2386 return Exit_NOTFOUND;
2387 }
2388
2389 search_command(argv0, argv[0], &ci, type);
2390
2391 wchar_t **namep = invoke_simple_command(&ci, argc, argv0, argv, false);
2392 if (namep != NULL)
2393 *namep = joinwcsarray(argv, L" ");
2394
2395 free(argv0);
2396 return laststatus;
2397 }
2398
2399 /* Prints info about the specified command.
2400 * If the command is not found, returns false. */
print_command_info(const wchar_t * commandname,enum srchcmdtype_T type,bool aliases,bool keywords,bool humanfriendly)2401 bool print_command_info(
2402 const wchar_t *commandname, enum srchcmdtype_T type,
2403 bool aliases, bool keywords, bool humanfriendly)
2404 {
2405 const char *msgfmt;
2406 char *name = NULL;
2407
2408 if (keywords && is_keyword(commandname)) {
2409 msgfmt = humanfriendly ? gt("%ls: a shell keyword\n") : "%ls\n";
2410 xprintf(msgfmt, commandname);
2411 return true;
2412 }
2413
2414 if (aliases) {
2415 if (print_alias_if_defined(commandname, humanfriendly)) {
2416 return true;
2417 } else {
2418 if (ferror(stdout))
2419 return false;
2420 }
2421 }
2422
2423 name = malloc_wcstombs(commandname);
2424 if (name == NULL)
2425 return false;
2426
2427 commandinfo_T ci;
2428 search_command(name, commandname, &ci, type);
2429 switch (ci.type) {
2430 case CT_NONE:
2431 if (humanfriendly)
2432 xerror(0, Ngt("no such command `%s'"), name);
2433 break;
2434 case CT_EXTERNALPROGRAM:
2435 print_command_absolute_path(name, ci.ci_path, humanfriendly);
2436 break;
2437 case CT_SPECIALBUILTIN:
2438 msgfmt = humanfriendly ? gt("%s: a special built-in\n") : "%s\n";
2439 xprintf(msgfmt, name);
2440 break;
2441 case CT_SEMISPECIALBUILTIN:
2442 msgfmt = humanfriendly ? gt("%s: a semi-special built-in\n")
2443 : "%s\n";
2444 xprintf(msgfmt, name);
2445 break;
2446 case CT_REGULARBUILTIN:;
2447 const char *cmdpath;
2448 if (type & SCT_STDPATH)
2449 cmdpath = get_command_path_default(name);
2450 else
2451 cmdpath = get_command_path(name, false);
2452 if (humanfriendly) {
2453 msgfmt = (cmdpath == NULL)
2454 ? Ngt("%s: a regular built-in (not found in $PATH)\n")
2455 : Ngt("%s: a regular built-in at %s\n");
2456 xprintf(gt(msgfmt), name, cmdpath);
2457 } else {
2458 xprintf("%s\n", (cmdpath == NULL) ? name : cmdpath);
2459 }
2460 break;
2461 case CT_FUNCTION:
2462 msgfmt = humanfriendly ? gt("%s: a function\n") : "%s\n";
2463 xprintf(msgfmt, name);
2464 break;
2465 }
2466
2467 free(name);
2468 return ci.type != CT_NONE;
2469 }
2470
2471 /* Prints the absolute path of the specified command. */
print_command_absolute_path(const char * name,const char * path,bool humanfriendly)2472 void print_command_absolute_path(
2473 const char *name, const char *path, bool humanfriendly)
2474 {
2475 if (path[0] == '/') {
2476 /* the path is already absolute */
2477 print_command_path(name, path, humanfriendly);
2478 return;
2479 }
2480
2481 xstrbuf_T abspath;
2482 sb_init(&abspath);
2483
2484 const wchar_t *wpwd = getvar(L VAR_PWD);
2485 if (wpwd != NULL) {
2486 int r = sb_printf(&abspath, "%ls", wpwd);
2487 if (r < 0 || !is_same_file(abspath.contents, ".")) {
2488 sb_truncate(&abspath, 0);
2489 }
2490 }
2491 if (abspath.length == 0) {
2492 char *pwd = xgetcwd();
2493 if (pwd != NULL)
2494 sb_catfree(&abspath, pwd);
2495 else
2496 sb_ccat(&abspath, '.'); /* last resort */
2497 }
2498
2499 if (abspath.length == 0 || abspath.contents[abspath.length - 1] != '/')
2500 sb_ccat(&abspath, '/');
2501
2502 sb_cat(&abspath, path);
2503
2504 print_command_path(name, abspath.contents, humanfriendly);
2505 sb_destroy(&abspath);
2506 }
2507
print_command_path(const char * name,const char * path,bool humanfriendly)2508 void print_command_path(
2509 const char *name, const char *path, bool humanfriendly)
2510 {
2511 if (humanfriendly)
2512 xprintf(gt("%s: an external command at %s\n"), name, path);
2513 else
2514 xprintf("%s\n", path);
2515 }
2516
2517 #if YASH_ENABLE_HELP
2518
2519 const char command_help[] = Ngt(
2520 "execute or identify a command"
2521 );
2522 const char command_syntax[] = Ngt(
2523 "\tcommand [-befp] command [argument...]\n"
2524 "\tcommand -v|-V [-abefkp] command...\n"
2525 );
2526
2527 const char type_help[] = Ngt(
2528 "identify a command"
2529 );
2530 const char type_syntax[] = Ngt(
2531 "\ttype command...\n"
2532 );
2533
2534 #endif
2535
2536 /* The "times" built-in. */
times_builtin(int argc,void ** argv)2537 int times_builtin(int argc __attribute__((unused)), void **argv)
2538 {
2539 const struct xgetopt_T *opt;
2540 xoptind = 0;
2541 while ((opt = xgetopt(argv, help_option, 0)) != NULL) {
2542 switch (opt->shortopt) {
2543 #if YASH_ENABLE_HELP
2544 case L'-':
2545 return print_builtin_help(ARGV(0));
2546 #endif
2547 default:
2548 return special_builtin_error(Exit_ERROR);
2549 }
2550 }
2551
2552 if (xoptind < argc)
2553 return special_builtin_error(too_many_operands_error(0));
2554
2555 double clock;
2556 struct tms tms;
2557 intmax_t sum, ssm, cum, csm;
2558 double sus, sss, cus, css;
2559 #define format_time(time, min, sec) \
2560 do { \
2561 double tsec = (time) / clock; \
2562 double m = trunc(tsec / 60.0); \
2563 (min) = (intmax_t) m; \
2564 (sec) = tsec - m * 60.0; \
2565 } while (0)
2566
2567 clock = sysconf(_SC_CLK_TCK);
2568 if (times(&tms) == (clock_t) -1) {
2569 xerror(errno, Ngt("cannot get the time data"));
2570 return special_builtin_error(Exit_FAILURE);
2571 }
2572 format_time(tms.tms_utime, sum, sus);
2573 format_time(tms.tms_stime, ssm, sss);
2574 format_time(tms.tms_cutime, cum, cus);
2575 format_time(tms.tms_cstime, csm, css);
2576 #undef format_time
2577
2578 xprintf("%jdm%fs %jdm%fs\n%jdm%fs %jdm%fs\n",
2579 sum, sus, ssm, sss, cum, cus, csm, css);
2580 return (yash_error_message_count == 0) ?
2581 Exit_SUCCESS : special_builtin_error(Exit_FAILURE);
2582 }
2583
2584 #if YASH_ENABLE_HELP
2585 const char times_help[] = Ngt(
2586 "print CPU time usage"
2587 );
2588 const char times_syntax[] = Ngt(
2589 "\ttimes\n"
2590 );
2591 #endif
2592
2593
2594 /* vim: set ts=8 sts=4 sw=4 noet tw=80: */
2595