Browse Source

The locking is implemented. When command is executing the enother clish can't execute commands. The action and config changes is atomic.

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

+ 17 - 6
clish.xsd

@@ -16,6 +16,20 @@
     <xs:element name="PARAM" type="param_t"/>
     <xs:element name="NAMESPACE" type="namespace_t"/>
     <xs:element name="CONFIG" type="config_t"/>
+
+
+    <!--
+*********************************************************** 
+* The common simple types
+*********************************************************** 
+-->
+    <xs:simpleType name="bool_t">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="true"/>
+            <xs:enumeration value="false"/>
+        </xs:restriction>
+    </xs:simpleType>
+
     <!--
 *********************************************************** 
 * <CLISH_MODULE> is the top level container.
@@ -189,6 +203,8 @@
 *                parameter. If the "args" attribute is given then this MUST be
 *                given also.
 *
+* [lock]         - the boolean field that specify to lock lockfile while
+*                command execution or not. Default is true.
 *
 ********************************************************
 -->
@@ -206,6 +222,7 @@
         <xs:attribute name="args" type="xs:string" use="optional"/>
         <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:complexType>
     <!--
 *******************************************************
@@ -250,12 +267,6 @@
 *           is "true" and "false".
 ********************************************************
     -->
-    <xs:simpleType name="bool_t">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="true"/>
-            <xs:enumeration value="false"/>
-        </xs:restriction>
-    </xs:simpleType>
 
     <xs:simpleType name="param_mode_t">
         <xs:restriction base="xs:string">

+ 2 - 0
clish/command.h

@@ -103,5 +103,7 @@ const clish_command_t * clish_command__get_orig(const clish_command_t * instance
 void clish_command__set_cfg_depth(clish_command_t * instance, const char * cfg_depth);
 unsigned clish_command__get_cfg_depth(const clish_command_t * instance,
 	const char *viewid, clish_pargv_t * pargv);
+bool_t clish_command__get_lock(const clish_command_t * instance);
+void clish_command__set_lock(clish_command_t * instance, bool_t lock);
 
 #endif				/* _clish_command_h */

+ 13 - 0
clish/command/command.c

@@ -37,6 +37,7 @@ clish_command_init(clish_command_t * this, const char *name, const char *text)
 	this->escape_chars = NULL;
 	this->args = NULL;
 	this->pview = NULL;
+	this->lock = BOOL_TRUE;
 
 	/* CONFIG params */
 	this->cfg_op = CLISH_CONFIG_NONE;
@@ -588,3 +589,15 @@ unsigned clish_command__get_cfg_depth(const clish_command_t * this,
 
 	return num;
 }
+
+/*--------------------------------------------------------- */
+bool_t clish_command__get_lock(const clish_command_t * this)
+{
+	return this->lock;
+}
+
+/*--------------------------------------------------------- */
+void clish_command__set_lock(clish_command_t * this, bool_t lock)
+{
+	this->lock = lock;
+}

+ 1 - 0
clish/command/private.h

@@ -20,6 +20,7 @@ struct clish_command_s {
 	clish_param_t *args;
 	const struct clish_command_s * link;
 	clish_view_t *pview;
+	bool_t lock;
 
 	/* CONFIG params:
 	 * TODO: create special structure for CONFIG params.

+ 5 - 0
clish/shell.h

@@ -24,6 +24,9 @@
 #include "view.h"
 #include "konf/net.h"
 
+#define CLISH_LOCK_PATH "/tmp/clish.lock"
+#define CLISH_LOCK_WAIT 20
+
 _BEGIN_C_DECL typedef struct clish_shell_s clish_shell_t;
 
 /*=====================================
@@ -330,6 +333,8 @@ char *clish_shell__get_line(const clish_command_t * cmd, clish_pargv_t * pargv);
 konf_client_t *clish_shell__get_client(const clish_shell_t * instance);
 FILE *clish_shell__get_istream(const clish_shell_t * instance);
 FILE *clish_shell__get_ostream(const clish_shell_t * instance);
+void clish_shell__set_lockfile(clish_shell_t * instance, const char * path);
+char * clish_shell__get_lockfile(clish_shell_t * instance);
 
 /* Context */
 typedef struct clish_context_s clish_context_t;

+ 1 - 0
clish/shell/private.h

@@ -79,6 +79,7 @@ struct clish_shell_s {
 	unsigned completion_pindex;
 	clish_param_t *param_depth;
 	clish_param_t *param_pwd;
+	char * lockfile;
 };
 
 /**

+ 2 - 0
clish/shell/shell_delete.c

@@ -63,6 +63,8 @@ static void clish_shell_fini(clish_shell_t * this)
 	/* Free internal params */
 	clish_param_delete(this->param_depth);
 	clish_param_delete(this->param_pwd);
+
+	lub_string_free(this->lockfile);
 }
 
 /*--------------------------------------------------------- */

+ 53 - 12
clish/shell/shell_execute.c

@@ -7,9 +7,12 @@
 
 #include <assert.h>
 #include <stdio.h>
+#include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <sys/stat.h>
+#include <sys/file.h>
 
 /*
  * These are the internal commands for this framework.
@@ -195,6 +198,8 @@ clish_shell_execute(clish_shell_t * this,
 	bool_t result = BOOL_TRUE;
 	const char *builtin;
 	char *script;
+	char *lock_path = clish_shell__get_lockfile(this);
+	int lock_fd = -1;
 
 	assert(NULL != cmd);
 
@@ -224,12 +229,43 @@ clish_shell_execute(clish_shell_t * this,
 		}
 	}
 
-	/* Execute action */
+	/* Lock the lockfile */
+	if (lock_path && clish_command__get_lock(cmd)) {
+		int i;
+		int res;
+		lock_fd = open(lock_path, O_RDONLY | O_CREAT, 00644);
+		if (-1 == lock_fd) {
+			fprintf(stderr, "Can't open lockfile %s.\n",
+				lock_path);
+			return BOOL_FALSE; /* can't open file */
+		}
+		for (i = 0; i < CLISH_LOCK_WAIT; i++) {
+			res = flock(lock_fd, LOCK_EX | LOCK_NB);
+			if (!res)
+				break;
+			if ((EBADF == errno) ||
+				(EINVAL == errno) ||
+				(ENOLCK == errno))
+				break;
+			if (EINTR == errno)
+				continue;
+			if (0 == i)
+				fprintf(stderr,
+					"Try to get lock. Please wait...\n");
+			sleep(1);
+		}
+		if (res) {
+			fprintf(stderr, "Can't get lock.\n");
+			return BOOL_FALSE; /* can't get the lock */
+		}
+	}
+
+	/* Execute ACTION */
 	builtin = clish_command__get_builtin(cmd);
 	script = clish_command__get_action(cmd, this->viewid, *pargv);
 	/* account for thread cancellation whilst running a script */
 	pthread_cleanup_push((void (*)(void *))clish_shell_cleanup_script,
-			     script);
+		script);
 	if (NULL != builtin) {
 		clish_shell_builtin_fn_t *callback;
 		lub_argv_t *argv = script ? lub_argv_new(script, 0) : NULL;
@@ -259,18 +295,21 @@ clish_shell_execute(clish_shell_t * this,
 	}
 	pthread_cleanup_pop(1);
 
-	if (BOOL_TRUE == result) {
-		clish_view_t *view = NULL;
-		char *viewid = NULL;
-
-		/* Now get the client to config operations */
-		if (this->client_hooks->config_fn)
-			this->client_hooks->config_fn(this, cmd, *pargv);
+	/* Call config callback */
+	if ((BOOL_TRUE == result) && this->client_hooks->config_fn)
+		this->client_hooks->config_fn(this, cmd, *pargv);
 
-		/* Move into the new view */
-		view = clish_command__get_view(cmd);
-		viewid = clish_command__get_viewid(cmd, this->viewid, *pargv);
+	/* Unlock the lockfile */
+	if (lock_fd != -1) {
+		flock(lock_fd, LOCK_UN);
+		close(lock_fd);
+	}
 
+	/* Move into the new view */
+	if (BOOL_TRUE == result) {
+		clish_view_t *view = clish_command__get_view(cmd);
+		char *viewid = clish_command__get_viewid(cmd,
+			this->viewid, *pargv);
 		if (NULL != view) {
 			/* Save the current config PWD */
 			char *line = clish_variable__get_line(cmd, *pargv);
@@ -287,10 +326,12 @@ clish_shell_execute(clish_shell_t * this,
 			this->viewid = viewid;
 		}
 	}
+
 	if (NULL != *pargv) {
 		clish_pargv_delete(*pargv);
 		*pargv = NULL;
 	}
+
 	return result;
 }
 

+ 4 - 0
clish/shell/shell_new.c

@@ -5,6 +5,9 @@
 
 #include <assert.h>
 #include <stdlib.h>
+
+#include "lub/string.h"
+
 /*-------------------------------------------------------- */
 static void
 clish_shell_init(clish_shell_t * this,
@@ -41,6 +44,7 @@ clish_shell_init(clish_shell_t * this,
 	this->cfg_pwdc = 0;
 	this->client = konf_client_new(KONFD_SOCKET_PATH);
 	this->completion_pargv = NULL;
+	this->lockfile = lub_string_dup(CLISH_LOCK_PATH);
 
 	/* Create internal ptypes and params */
 	/* Current depth */

+ 26 - 1
clish/shell/shell_pwd.c

@@ -44,6 +44,7 @@ clish_shell__set_pwd(clish_shell_t * this, unsigned index,
 	this->cfg_pwdv[index]->viewid = viewid ? lub_string_dup(viewid) : NULL;
 }
 
+/*--------------------------------------------------------- */
 char *clish_shell__get_pwd_line(const clish_shell_t * this, unsigned index)
 {
 	if (index >= this->cfg_pwdc)
@@ -52,6 +53,7 @@ char *clish_shell__get_pwd_line(const clish_shell_t * this, unsigned index)
 	return this->cfg_pwdv[index]->line;
 }
 
+/*--------------------------------------------------------- */
 char *clish_shell__get_pwd_full(const clish_shell_t * this, unsigned depth)
 {
 	char *pwd = NULL;
@@ -75,7 +77,7 @@ char *clish_shell__get_pwd_full(const clish_shell_t * this, unsigned depth)
 	return pwd;
 }
 
-
+/*--------------------------------------------------------- */
 clish_view_t *clish_shell__get_pwd_view(const clish_shell_t * this, unsigned index)
 {
 	if (index >= this->cfg_pwdc)
@@ -84,6 +86,7 @@ clish_view_t *clish_shell__get_pwd_view(const clish_shell_t * this, unsigned ind
 	return this->cfg_pwdv[index]->view;
 }
 
+/*--------------------------------------------------------- */
 char *clish_shell__get_pwd_viewid(const clish_shell_t * this, unsigned index)
 {
 	if (index >= this->cfg_pwdc)
@@ -92,7 +95,29 @@ char *clish_shell__get_pwd_viewid(const clish_shell_t * this, unsigned index)
 	return this->cfg_pwdv[index]->viewid;
 }
 
+/*--------------------------------------------------------- */
 konf_client_t *clish_shell__get_client(const clish_shell_t * this)
 {
 	return this->client;
 }
+
+/*--------------------------------------------------------- */
+void clish_shell__set_lockfile(clish_shell_t * this, const char * path)
+{
+	if (!this)
+		return;
+
+	lub_string_free(this->lockfile);
+	this->lockfile = NULL;
+	if (path)
+		this->lockfile = lub_string_dup(path);
+}
+
+/*--------------------------------------------------------- */
+char * clish_shell__get_lockfile(clish_shell_t * this)
+{
+	if (!this)
+		return NULL;
+
+	return this->lockfile;
+}

+ 8 - 0
clish/shell/shell_tinyxml_read.cpp

@@ -203,6 +203,7 @@ process_command(clish_shell_t * shell, TiXmlElement * element, void *parent)
 		const char *escape_chars = element->Attribute("escape_chars");
 		const char *args_name = element->Attribute("args");
 		const char *args_help = element->Attribute("args_help");
+		const char *lock = element->Attribute("lock");
 
 		clish_command_t *old = clish_view_find_command(v, name, BOOL_FALSE);
 
@@ -253,6 +254,12 @@ process_command(clish_shell_t * shell, TiXmlElement * element, void *parent)
 			if (NULL != viewid) {
 				clish_command__set_viewid(cmd, viewid);
 			}
+			/* lock field */
+			if (lock && (lub_string_nocasecmp(lock, "false") == 0))
+				clish_command__set_lock(cmd, BOOL_FALSE);
+			else
+				clish_command__set_lock(cmd, BOOL_TRUE);
+
 			process_children(shell, element, cmd);
 		}
 	}
@@ -280,6 +287,7 @@ process_startup(clish_shell_t * shell, TiXmlElement * element, void *parent)
 
 	/* create a command with NULL help */
 	cmd = clish_view_new_command(v, "startup", NULL);
+	clish_command__set_lock(cmd, BOOL_FALSE);
 
 	// define the view which this command changes to
 	clish_view_t *next = clish_shell_find_create_view(shell, view, NULL);

+ 1 - 1
konf/tree/tree.c

@@ -161,7 +161,7 @@ void konf_tree_fprintf(konf_tree_t * this, FILE * stream,
 			fprintf(stream, "!\n");
 		fprintf(stream, "%s", space ? space : "");
 		if (seq && (konf_tree__get_seq_num(this) != 0))
-			fprintf(stream, "%02u ", konf_tree__get_seq_num(this));
+			fprintf(stream, "%u ", konf_tree__get_seq_num(this));
 		fprintf(stream, "%s\n", this->line);
 		free(space);
 	}