Browse Source

The implementation of non-interruptable action. The Ctrl^C can be ignored for actions (default behaviour).

git-svn-id: https://klish.googlecode.com/svn/trunk@346 0eaa4687-2ee9-07dd-09d9-bcdd2d2dd5fb
Serj Kalichev 13 years ago
parent
commit
dd00b38fe3

+ 1 - 0
clish.xsd

@@ -241,6 +241,7 @@
         <xs:attribute name="args_help" type="xs:string" use="optional"/>
         <xs:attribute name="escape_chars" type="xs:string" use="optional"/>
         <xs:attribute name="lock" type="bool_t" use="optional" default="true"/>
+        <xs:attribute name="interrupt" type="bool_t" use="optional" default="false"/>
     </xs:complexType>
     <!--
 *******************************************************

+ 2 - 0
clish/command.h

@@ -121,5 +121,7 @@ void clish_command__set_alias_view(clish_command_t * instance,
 clish_view_t * clish_command__get_alias_view(const clish_command_t * instance);
 void clish_command__set_dynamic(clish_command_t * instance, bool_t dynamic);
 bool_t clish_command__get_dynamic(const clish_command_t * instance);
+bool_t clish_command__get_interrupt(const clish_command_t * instance);
+void clish_command__set_interrupt(clish_command_t * instance, bool_t interrupt);
 
 #endif				/* _clish_command_h */

+ 12 - 0
clish/command/command.c

@@ -39,6 +39,7 @@ clish_command_init(clish_command_t * this, const char *name, const char *text)
 	this->args = NULL;
 	this->pview = NULL;
 	this->lock = BOOL_TRUE;
+	this->interrupt = BOOL_FALSE;
 	this->dynamic = BOOL_FALSE;
 
 	/* ACTION params */
@@ -715,3 +716,14 @@ const clish_command_t * clish_command__get_cmd(const clish_command_t * this)
 	return NULL;
 }
 
+/*--------------------------------------------------------- */
+bool_t clish_command__get_interrupt(const clish_command_t * this)
+{
+	return this->interrupt;
+}
+
+/*--------------------------------------------------------- */
+void clish_command__set_interrupt(clish_command_t * this, bool_t interrupt)
+{
+	this->interrupt = interrupt;
+}

+ 1 - 0
clish/command/private.h

@@ -22,6 +22,7 @@ struct clish_command_s {
 	char *alias;
 	clish_view_t *pview;
 	bool_t lock;
+	bool_t interrupt;
 	bool_t dynamic; /* Is command dynamically created */
 
 	/* ACTION params: */

+ 31 - 0
clish/shell/shell_execute.c

@@ -13,6 +13,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 #include <sys/file.h>
+#include <signal.h>
 
 /*
  * These are the internal commands for this framework.
@@ -188,6 +189,8 @@ clish_shell_execute(clish_shell_t * this,
 	char *script;
 	char *lock_path = clish_shell__get_lockfile(this);
 	int lock_fd = -1;
+	sigset_t old_sigs;
+	struct sigaction old_sigint, old_sigquit;
 
 	assert(NULL != cmd);
 
@@ -248,6 +251,19 @@ clish_shell_execute(clish_shell_t * this,
 		}
 	}
 
+	/* Ignore and block SIGINT and SIGQUIT */
+	if (!clish_command__get_interrupt(cmd)) {
+		struct sigaction sa = { 0 };
+		sigset_t sigs;
+		sa.sa_handler = SIG_IGN;
+		sigaction(SIGINT, &sa, &old_sigint);
+		sigaction(SIGQUIT, &sa, &old_sigquit);
+		sigemptyset(&sigs);
+		sigaddset(&sigs, SIGINT);
+		sigaddset(&sigs, SIGQUIT);
+		sigprocmask(SIG_BLOCK, &sigs, &old_sigs);
+	}
+
 	/* Execute ACTION */
 	builtin = clish_command__get_builtin(cmd);
 	script = clish_command__get_action(cmd, this->viewid, pargv);
@@ -282,6 +298,21 @@ clish_shell_execute(clish_shell_t * this,
 	}
 	pthread_cleanup_pop(1);
 
+	/* Restore SIGINT and SIGQUIT */
+	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);
+	}
+
 	/* Call config callback */
 	if ((BOOL_TRUE == result) && this->client_hooks->config_fn)
 		this->client_hooks->config_fn(this, cmd, pargv);

+ 6 - 0
clish/shell/shell_tinyxml_read.cpp

@@ -195,6 +195,7 @@ process_command(clish_shell_t * shell, TiXmlElement * element, void *parent)
 	const char *args_name = element->Attribute("args");
 	const char *args_help = element->Attribute("args_help");
 	const char *lock = element->Attribute("lock");
+	const char *interrupt = element->Attribute("interrupt");
 	const char *ref = element->Attribute("ref");
 
 	if (NULL != access) {
@@ -290,6 +291,11 @@ process_command(clish_shell_t * shell, TiXmlElement * element, void *parent)
 		clish_command__set_lock(cmd, BOOL_FALSE);
 	else
 		clish_command__set_lock(cmd, BOOL_TRUE);
+	/* interrupt field */
+	if (interrupt && (lub_string_nocasecmp(interrupt, "true") == 0))
+		clish_command__set_interrupt(cmd, BOOL_TRUE);
+	else
+		clish_command__set_interrupt(cmd, BOOL_FALSE);
 
 	/* Set alias */
 	if (alias_name) {