diff --git a/CHANGELOG.md b/CHANGELOG.md index 89d8a4fe..81dc1a13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,7 @@ Developers may need to change their code * Plugin context check before and after all callbacks. * Check blocked signals and signal handlers + * Check termios settings * Any changes to context are logged at loglevel WARNING * Added set/get pointer API to clixon_data: * clicon_ptr_get(), clicon_ptr_set(), diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index d65a150a..e32509f2 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -165,17 +165,17 @@ cli_signal_flush(clicon_handle h) sigfn_t h1, h2, h3, h4; - set_signal (SIGTSTP, SIG_IGN, &h1); - set_signal (SIGQUIT, SIG_IGN, &h2); - set_signal (SIGCHLD, SIG_IGN, &h3); - set_signal (SIGINT, SIG_IGN, &h4); + set_signal(SIGTSTP, SIG_IGN, &h1); + set_signal(SIGQUIT, SIG_IGN, &h2); + set_signal(SIGCHLD, SIG_IGN, &h3); + set_signal(SIGINT, SIG_IGN, &h4); cli_signal_unblock (h); - set_signal (SIGTSTP, h1, NULL); - set_signal (SIGQUIT, h2, NULL); - set_signal (SIGCHLD, h3, NULL); - set_signal (SIGINT, h4, NULL); + set_signal(SIGTSTP, h1, NULL); + set_signal(SIGQUIT, h2, NULL); + set_signal(SIGCHLD, h3, NULL); + set_signal(SIGINT, h4, NULL); cli_signal_block (h); } @@ -562,9 +562,10 @@ cli_start_shell(clicon_handle h, int retval = -1; char bcmd[128]; cg_var *cv1 = cvec_i(vars, 1); - + sigset_t oldsigset; + struct sigaction oldsigaction[32] = {0,}; + cmd = (cvec_len(vars)>1 ? cv_string_get(cv1) : NULL); - if ((pw = getpwuid(getuid())) == NULL){ clicon_err(OE_UNIX, errno, "getpwuid"); goto done; @@ -575,6 +576,9 @@ cli_start_shell(clicon_handle h, goto done; } endpwent(); + + if (clixon_signal_save(&oldsigset, oldsigaction) < 0) + goto done; cli_signal_flush(h); cli_signal_unblock(h); if (cmd){ @@ -598,6 +602,8 @@ cli_start_shell(clicon_handle h, goto done; } #endif + if (clixon_signal_restore(&oldsigset, oldsigaction) < 0) + goto done; retval = 0; done: return retval; diff --git a/lib/clixon/clixon_sig.h b/lib/clixon/clixon_sig.h index 317c7079..07249374 100644 --- a/lib/clixon/clixon_sig.h +++ b/lib/clixon/clixon_sig.h @@ -47,6 +47,8 @@ typedef void (*sigfn_t)(int); * Prototypes */ int set_signal(int signo, void (*handler)(int), void (**oldhandler)(int)); +int clixon_signal_save(sigset_t *sigset, struct sigaction sigaction_vec[32]); +int clixon_signal_restore(sigset_t *sigset, struct sigaction sigaction_vec[32]); void clicon_signal_block(int); void clicon_signal_unblock(int); diff --git a/lib/src/clixon_event.c b/lib/src/clixon_event.c index 736c7541..9dad4dfe 100644 --- a/lib/src/clixon_event.c +++ b/lib/src/clixon_event.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/lib/src/clixon_plugin.c b/lib/src/clixon_plugin.c index 18f15efd..2bebbcf3 100644 --- a/lib/src/clixon_plugin.c +++ b/lib/src/clixon_plugin.c @@ -47,7 +47,8 @@ #include #include #include - +#include +#include #include #include @@ -71,12 +72,13 @@ * Private types */ /*! Structure for checking status before and after a plugin call - * Currently signal settings: blocked and handlers, could be extended to more + * Currently signal settings: blocked and handlers, and termios * @see plugin_context_check */ struct plugin_context { sigset_t pc_sigset; /* See sigprocmask(2) */ struct sigaction pc_sigaction_vec[32]; /* See sigaction(2) */ + struct termios pc_termios; /* See termios(3) */ }; /* Internal plugin structure with dlopen() handle and plugin_api @@ -518,6 +520,7 @@ plugin_context_get(void) goto done; } memset(pc, 0, sizeof(*pc)); + if (sigprocmask(0, NULL, &pc->pc_sigset) < 0){ clicon_err(OE_UNIX, errno, "sigprocmask"); goto done; @@ -536,6 +539,10 @@ plugin_context_get(void) pc->pc_sigaction_vec[i].sa_flags &= ~0x04000000; #endif } + if (isatty(0) && tcgetattr(0, &pc->pc_termios) < 0){ + clicon_err(OE_UNIX, errno, "tcgetattr %d", errno); + goto done; + } return pc; done: if (pc) @@ -564,15 +571,48 @@ plugin_context_check(plugin_context_t *oldpc0, const char *fn) { int retval = -1; - int failed; + int failed = 0; int i; struct plugin_context *oldpc = oldpc0; struct plugin_context *newpc = NULL; if ((newpc = plugin_context_get()) == NULL) goto done; + if (oldpc->pc_termios.c_iflag != newpc->pc_termios.c_iflag){ + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed termios input modes from 0x%x to 0x%x", __FUNCTION__, + name, fn, + oldpc->pc_termios.c_iflag, + newpc->pc_termios.c_iflag); + failed++; + } + if (oldpc->pc_termios.c_oflag != newpc->pc_termios.c_oflag){ + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed termios output modes from 0x%x to 0x%x", __FUNCTION__, + name, fn, + oldpc->pc_termios.c_oflag, + newpc->pc_termios.c_oflag); + failed++; + } + if (oldpc->pc_termios.c_cflag != newpc->pc_termios.c_cflag){ + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed termios control modes from 0x%x to 0x%x", __FUNCTION__, + name, fn, + oldpc->pc_termios.c_cflag, + newpc->pc_termios.c_cflag); + failed++; + } + if (oldpc->pc_termios.c_lflag != newpc->pc_termios.c_lflag){ + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed termios local modes from 0x%x to 0x%x", __FUNCTION__, + name, fn, + oldpc->pc_termios.c_lflag, + newpc->pc_termios.c_lflag); + failed++; + } + /* XXX pc_termios.cc_t c_cc[NCCS] not checked */ +#if 0 + /* In case you want early detection and crash. But otherwise it is recommended that + * the caller looks for retval == 0 */ + assert(failed == 0); +#endif for (i=1; i<32; i++){ - failed = 0; if (sigismember(&oldpc->pc_sigset, i) != sigismember(&newpc->pc_sigset, i)){ clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed blocking of signal %s(%d) from %d to %d", __FUNCTION__, name, fn, strsignal(i), i, @@ -600,10 +640,10 @@ plugin_context_check(plugin_context_t *oldpc0, * the caller looks for retval == 0 */ assert(failed == 0); #endif - if (failed) - goto fail; - } + if (failed) + goto fail; + retval = 1; /* OK */ done: if (newpc) diff --git a/lib/src/clixon_sig.c b/lib/src/clixon_sig.c index 16cb3176..611a27a8 100644 --- a/lib/src/clixon_sig.c +++ b/lib/src/clixon_sig.c @@ -121,6 +121,58 @@ clicon_signal_unblock(int sig) sigprocmask(SIG_UNBLOCK, &set, NULL); } +/*! Save complete signal context + */ +int +clixon_signal_save(sigset_t *sigset, + struct sigaction sigaction_vec[32]) +{ + int retval = -1; + int i; + + if (sigprocmask(0, NULL, sigset) < 0){ + clicon_err(OE_UNIX, errno, "sigprocmask"); + goto done; + } + for (i=1; i<32; i++){ + if (sigaction(i, NULL, &sigaction_vec[i]) < 0){ + clicon_err(OE_UNIX, errno, "sigaction"); + goto done; + } + } + retval = 0; + done: + return retval; +} + +/*! Restore complete signal context + * + * Note: sigaction may not restore SIGKILL or SIGSTOP, which cannot be caught or ignored. + */ +int +clixon_signal_restore(sigset_t *sigset, + struct sigaction sigaction_vec[32]) +{ + int retval = -1; + int i; + + if (sigprocmask(0, sigset, NULL) < 0){ + clicon_err(OE_UNIX, errno, "sigprocmask"); + goto done; + } + for (i=1; i<32; i++){ + if (i == SIGKILL || i == SIGSTOP) + continue; + if (sigaction(i, &sigaction_vec[i], NULL) < 0){ + clicon_err(OE_UNIX, errno, "sigaction"); + goto done; + } + } + retval = 0; + done: + return retval; +} + /*! Read pidfile and return pid using file descriptor * * @param[in] pidfile Name of pidfile