/*--------------------------------------------------------- */ void clish_shell__fini_pwd(clish_shell_pwd_t *pwd) { clish_var_t *var; lub_string_free(pwd->line); lub_string_free(pwd->cmd); if (pwd->prefix) lub_string_free(pwd->prefix); pwd->view = NULL; clish_pargv_delete(pwd->pargv); /* delete each VAR held */ while ((var = lub_bintree_findfirst(&pwd->viewid))) { lub_bintree_remove(&pwd->viewid, var); clish_var_delete(var); } }
/*----------------------------------------------------------- */ 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 main(int argc, char **argv) { int res = -1; konf_client_t *client = NULL; konf_buf_t *buf = NULL; char *line = NULL; char *str = NULL; const char *socket_path = KONFD_SOCKET_PATH; int i = 0; /* Signal vars */ struct sigaction sigpipe_act; sigset_t sigpipe_set; static const char *shortopts = "hvs:"; #ifdef HAVE_GETOPT_LONG static const struct option longopts[] = { {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'v'}, {"socket", 1, NULL, 's'}, {NULL, 0, NULL, 0} }; #endif /* Ignore SIGPIPE */ sigemptyset(&sigpipe_set); sigaddset(&sigpipe_set, SIGPIPE); sigpipe_act.sa_flags = 0; sigpipe_act.sa_mask = sigpipe_set; sigpipe_act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sigpipe_act, NULL); /* Parse command line options */ while(1) { int opt; #ifdef HAVE_GETOPT_LONG opt = getopt_long(argc, argv, shortopts, longopts, NULL); #else opt = getopt(argc, argv, shortopts); #endif if (-1 == opt) break; switch (opt) { case 's': socket_path = optarg; break; case 'h': help(0, argv[0]); exit(0); break; case 'v': version(VERSION); exit(0); break; default: help(-1, argv[0]); exit(-1); break; } } /* Get request line from the args */ for (i = optind; i < argc; i++) { char *space = NULL; if (NULL != line) lub_string_cat(&line, " "); space = strchr(argv[i], ' '); if (space) lub_string_cat(&line, "\""); str = lub_string_encode(argv[i], escape_chars); lub_string_cat(&line, str); lub_string_free(str); if (space) lub_string_cat(&line, "\""); } if (!line) { help(-1, argv[0]); goto err; } #ifdef DEBUG fprintf(stderr, "REQUEST: %s\n", line); #endif if (!(client = konf_client_new(socket_path))) { fprintf(stderr, "Error: Can't create internal data structures.\n"); goto err; } if (konf_client_connect(client) < 0) { fprintf(stderr, "Error: Can't connect to %s socket.\n", socket_path); goto err; } if (konf_client_send(client, line) < 0) { fprintf(stderr, "Error: Can't send request to %s socket.\n", socket_path); goto err; } if (konf_client_recv_answer(client, &buf) < 0) { fprintf(stderr, "Error: The error code from the konfd daemon.\n"); goto err; } if (buf) { konf_buf_lseek(buf, 0); while ((str = konf_buf_preparse(buf))) { if (strlen(str) == 0) { lub_string_free(str); break; } fprintf(stdout, "%s\n", str); lub_string_free(str); } konf_buf_delete(buf); } res = 0; err: lub_string_free(line); konf_client_free(client); return res; }
/*----------------------------------------------------------- */ 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; }