/*----------------------------------------------------------- */ int clish_shell_exec_action(clish_context_t *context, char **out) { int result = -1; clish_sym_t *sym; char *script; clish_hook_action_fn_t *func = NULL; const clish_action_t *action = clish_context__get_action(context); clish_shell_t *shell = clish_context__get_shell(context); if (!(sym = clish_action__get_builtin(action))) return 0; if (shell->dryrun && !clish_sym__get_permanent(sym)) return 0; if (!(func = clish_sym__get_func(sym))) { fprintf(stderr, "Error: Default ACTION symbol is not specified.\n"); return -1; } script = clish_shell_expand(clish_action__get_script(action), SHELL_VAR_ACTION, context); result = func(context, script, out); lub_string_free(script); return result; }
/*----------------------------------------------------------- */ int clish_shell_exec_action(clish_context_t *context, char **out) { int result = -1; const clish_sym_t *sym; char *script; const void *func = NULL; /* We don't know the func API at this time */ const clish_action_t *action = clish_context__get_action(context); clish_shell_t *shell = clish_context__get_shell(context); bool_t intr = clish_action__get_interrupt(action); /* Signal vars */ struct sigaction old_sigint, old_sigquit, old_sighup; struct sigaction sa; sigset_t old_sigs; if (!(sym = clish_action__get_builtin(action))) return 0; if (shell->dryrun && !clish_sym__get_permanent(sym)) return 0; if (!(func = clish_sym__get_func(sym))) { fprintf(stderr, "Error: Default ACTION symbol is not specified.\n"); return -1; } script = clish_shell_expand(clish_action__get_script(action), SHELL_VAR_ACTION, context); /* Ignore and block SIGINT, SIGQUIT, SIGHUP. * The SIG_IGN is not a case because it will be inherited * while a fork(). It's necessary to ignore signals because * the klish itself and ACTION script share the same terminal. */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = sigignore; /* Empty signal handler */ sigaction(SIGINT, &sa, &old_sigint); sigaction(SIGQUIT, &sa, &old_sigquit); sigaction(SIGHUP, &sa, &old_sighup); /* Block signals for children processes. The block state is inherited. */ if (!intr) { sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs, SIGINT); sigaddset(&sigs, SIGQUIT); sigaddset(&sigs, SIGHUP); sigprocmask(SIG_BLOCK, &sigs, &old_sigs); } /* Find out the function API */ /* CLISH_SYM_API_SIMPLE */ if (clish_sym__get_api(sym) == CLISH_SYM_API_SIMPLE) { result = ((clish_hook_action_fn_t *)func)(context, script, out); /* CLISH_SYM_API_STDOUT and output is not needed */ } else if ((clish_sym__get_api(sym) == CLISH_SYM_API_STDOUT) && (!out)) { result = ((clish_hook_oaction_fn_t *)func)(context, script); /* CLISH_SYM_API_STDOUT and outpus is needed */ } else if (clish_sym__get_api(sym) == CLISH_SYM_API_STDOUT) { result = clish_shell_exec_oaction((clish_hook_oaction_fn_t *)func, context, script, out); } /* Restore SIGINT, SIGQUIT, SIGHUP */ if (!intr) { sigprocmask(SIG_SETMASK, &old_sigs, NULL); /* Is the signals delivery guaranteed here (before sigaction restore) for previously blocked and pending signals? The simple test is working well. I don't want to use sigtimedwait() function because it needs a realtime extensions. The sigpending() with the sleep() is not nice too. Report bug if clish will get the SIGINT after non-interruptable action. */ } sigaction(SIGINT, &old_sigint, NULL); sigaction(SIGQUIT, &old_sigquit, NULL); sigaction(SIGHUP, &old_sighup, NULL); lub_string_free(script); return result; }