/* Open a file and interpret it as a script in the context of a new thread. Whether the script continues after command, but not script, errors depends on the value of the stop_on_error flag. */ static int clish_source_internal(clish_context_t *context, const char *fn, bool_t stop_on_error) { int result = -1; const char *filename = fn; struct stat fileStat; /* the exception proves the rule... */ clish_shell_t *this = clish_context__get_shell(context); /* * Check file specified is not a directory */ if ((0 == stat((char *)filename, &fileStat)) && (!S_ISDIR(fileStat.st_mode))) { /* * push this file onto the file stack associated with this * session. This will be closed by clish_shell_pop_file() * when it is finished with. */ result = clish_shell_push_file(this, filename, stop_on_error); } return result ? -1 : 0; }
/*----------------------------------------------------------------------- */ int clish_shell_keypress_fn(tinyrl_t *tinyrl, int key) { clish_context_t *context = tinyrl__get_context(tinyrl); clish_shell_t *this = clish_context__get_shell(context); if (this->wdog_active) { this->wdog_active = BOOL_FALSE; tinyrl__set_timeout(tinyrl, this->idle_timeout); } return 0; }
/*----------------------------------------------------------- */ const void *clish_shell_check_hook(const clish_context_t *clish_context, int type) { clish_sym_t *sym; clish_shell_t *shell = clish_context__get_shell(clish_context); const void *func; if (!(sym = shell->hooks[type])) return NULL; if (shell->dryrun && !clish_sym__get_permanent(sym)) return NULL; if (!(func = clish_sym__get_func(sym))) return NULL; return func; }
/*----------------------------------------------------------------------- */ int clish_shell_timeout_fn(tinyrl_t *tinyrl) { clish_context_t *context = tinyrl__get_context(tinyrl); clish_shell_t *this = clish_context__get_shell(context); /* Idle timeout */ if (!this->wdog_active) { tinyrl_crlf(tinyrl); fprintf(stderr, "Warning: Idle timeout. The session will be closed.\n"); /* Return -1 to close session on timeout */ return -1; } /* Watchdog timeout */ clish_shell_wdog(this); this->wdog_active = BOOL_FALSE; tinyrl__set_timeout(tinyrl, this->idle_timeout); return 0; }
/*----------------------------------------------------------- */ 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_execute(clish_context_t *context, char **out) { clish_shell_t *this = clish_context__get_shell(context); const clish_command_t *cmd = clish_context__get_cmd(context); int result = 0; const char *lock_path = clish_shell__get_lockfile(this); int lock_fd = -1; clish_view_t *cur_view = clish_shell__get_view(this); unsigned int saved_wdog_timeout = this->wdog_timeout; assert(cmd); /* Pre-change view if the command is from another depth/view */ { clish_view_restore_e restore = clish_command__get_restore(cmd); if ((CLISH_RESTORE_VIEW == restore) && (clish_command__get_pview(cmd) != cur_view)) { clish_view_t *view = clish_command__get_pview(cmd); clish_shell__set_pwd(this, NULL, view, NULL, context); } else if ((CLISH_RESTORE_DEPTH == restore) && (clish_command__get_depth(cmd) < this->depth)) { this->depth = clish_command__get_depth(cmd); } } /* Lock the lockfile */ if (lock_path && clish_action__get_lock(clish_command__get_action(cmd))) { lock_fd = clish_shell_lock(lock_path); if (-1 == lock_fd) { result = -1; goto error; /* Can't set lock */ } } /* Execute ACTION */ clish_context__set_action(context, clish_command__get_action(cmd)); result = clish_shell_exec_action(context, out); /* Call config callback */ if (!result) clish_shell_exec_config(context); /* Call logging callback */ if (clish_shell__get_log(this) && clish_shell_check_hook(context, CLISH_SYM_TYPE_LOG)) { char *full_line = clish_shell__get_full_line(context); clish_shell_exec_log(context, full_line, result); lub_string_free(full_line); } if (clish_shell__get_canon_out(this) && !clish_command__get_internal(cmd)) { char *space = NULL; char *full_line = clish_shell__get_full_line(context); if (this->depth > 0) { space = malloc(this->depth + 1); memset(space, ' ', this->depth); space[this->depth] = '\0'; } printf("%s%s\n", space ? space : "", full_line); lub_string_free(full_line); if (space) free(space); } /* Unlock the lockfile */ if (lock_fd != -1) clish_shell_unlock(lock_fd); /* Move into the new view */ if (!result) { char *viewname = clish_shell_expand(clish_command__get_viewname(cmd), SHELL_VAR_NONE, context); if (viewname) { /* Search for the view */ clish_view_t *view = clish_shell_find_view(this, viewname); if (!view) fprintf(stderr, "System error: Can't " "change view to %s\n", viewname); lub_string_free(viewname); /* Save the PWD */ if (view) { char *line = clish_shell__get_line(context); clish_shell__set_pwd(this, line, view, clish_command__get_viewid(cmd), context); lub_string_free(line); } } } /* Set appropriate timeout. Workaround: Don't turn on watchdog on the "set watchdog <timeout>" command itself. */ if (this->wdog_timeout && saved_wdog_timeout) { tinyrl__set_timeout(this->tinyrl, this->wdog_timeout); this->wdog_active = BOOL_TRUE; fprintf(stderr, "Warning: The watchdog is active. Timeout is %u " "seconds.\nWarning: Press any key to stop watchdog.\n", this->wdog_timeout); } else tinyrl__set_timeout(this->tinyrl, this->idle_timeout); error: 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; }
/*----------------------------------------------------------- */ int clish_shell_execute(clish_context_t *context, char **out) { clish_shell_t *this = clish_context__get_shell(context); const clish_command_t *cmd = clish_context__get_cmd(context); int result = 0; char *lock_path = clish_shell__get_lockfile(this); int lock_fd = -1; sigset_t old_sigs; struct sigaction old_sigint, old_sigquit, old_sighup; clish_view_t *cur_view = clish_shell__get_view(this); unsigned int saved_wdog_timeout = this->wdog_timeout; assert(cmd); /* Pre-change view if the command is from another depth/view */ { clish_view_restore_t restore = clish_command__get_restore(cmd); if ((CLISH_RESTORE_VIEW == restore) && (clish_command__get_pview(cmd) != cur_view)) { clish_view_t *view = clish_command__get_pview(cmd); clish_shell__set_pwd(this, NULL, view, NULL, context); } else if ((CLISH_RESTORE_DEPTH == restore) && (clish_command__get_depth(cmd) < this->depth)) { this->depth = clish_command__get_depth(cmd); } } /* Lock the lockfile */ if (lock_path && clish_command__get_lock(cmd)) { lock_fd = clish_shell_lock(lock_path); if (-1 == lock_fd) { result = -1; goto error; /* Can't set lock */ } } /* Ignore and block SIGINT, SIGQUIT, SIGHUP */ if (!clish_command__get_interrupt(cmd)) { struct sigaction sa; sigset_t sigs; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = SIG_IGN; sigaction(SIGINT, &sa, &old_sigint); sigaction(SIGQUIT, &sa, &old_sigquit); sigaction(SIGHUP, &sa, &old_sighup); sigemptyset(&sigs); sigaddset(&sigs, SIGINT); sigaddset(&sigs, SIGQUIT); sigaddset(&sigs, SIGHUP); sigprocmask(SIG_BLOCK, &sigs, &old_sigs); } /* Execute ACTION */ clish_context__set_action(context, clish_command__get_action(cmd)); result = clish_shell_exec_action(context, out); /* Restore SIGINT, SIGQUIT, SIGHUP */ if (!clish_command__get_interrupt(cmd)) { 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 bacause 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); } /* Call config callback */ if (!result) clish_shell_exec_config(context); /* Call logging callback */ if (clish_shell__get_log(this) && clish_shell_check_hook(context, CLISH_SYM_TYPE_LOG)) { char *full_line = clish_shell__get_full_line(context); clish_shell_exec_log(context, full_line, result); lub_string_free(full_line); } /* Unlock the lockfile */ if (lock_fd != -1) clish_shell_unlock(lock_fd); /* Move into the new view */ if (!result) { char *viewname = clish_shell_expand(clish_command__get_viewname(cmd), SHELL_VAR_NONE, context); if (viewname) { /* Search for the view */ clish_view_t *view = clish_shell_find_view(this, viewname); if (!view) fprintf(stderr, "System error: Can't " "change view to %s\n", viewname); lub_string_free(viewname); /* Save the PWD */ if (view) { char *line = clish_shell__get_line(context); clish_shell__set_pwd(this, line, view, clish_command__get_viewid(cmd), context); lub_string_free(line); } } } /* Set appropriate timeout. Workaround: Don't turn on watchdog on the "set watchdog <timeout>" command itself. */ if (this->wdog_timeout && saved_wdog_timeout) { tinyrl__set_timeout(this->tinyrl, this->wdog_timeout); this->wdog_active = BOOL_TRUE; fprintf(stderr, "Warning: The watchdog is active. Timeout is %u " "seconds.\nWarning: Press any key to stop watchdog.\n", this->wdog_timeout); } else tinyrl__set_timeout(this->tinyrl, this->idle_timeout); error: return result; }