Browse Source

The stdout is auto-grabbed for osym() symbols

Serj Kalichev 8 years ago
parent
commit
cf35f2045d

+ 2 - 2
clish/plugin.h

@@ -99,9 +99,9 @@ clish_sym_t *clish_plugin_add_sym(clish_plugin_t *instance,
 clish_sym_t *clish_plugin_add_psym(clish_plugin_t *instance,
 	clish_hook_action_fn_t *func, const char *name);
 clish_sym_t *clish_plugin_add_osym(clish_plugin_t *instance,
-	clish_hook_action_fn_t *func, const char *name);
+	clish_hook_oaction_fn_t *func, const char *name);
 clish_sym_t *clish_plugin_add_posym(clish_plugin_t *instance,
-	clish_hook_action_fn_t *func, const char *name);
+	clish_hook_oaction_fn_t *func, const char *name);
 clish_sym_t *clish_plugin_add_hook(clish_plugin_t *instance,
 	void *func, const char *name, int type);
 clish_sym_t *clish_plugin_add_phook(clish_plugin_t *instance,

+ 6 - 4
clish/plugin/plugin.c

@@ -238,11 +238,12 @@ clish_sym_t *clish_plugin_add_psym(clish_plugin_t *this,
 
 /*--------------------------------------------------------- */
 clish_sym_t *clish_plugin_add_osym(clish_plugin_t *this,
-	clish_hook_action_fn_t *func, const char *name)
+	clish_hook_oaction_fn_t *func, const char *name)
 {
 	clish_sym_t *s;
 
-	if (!(s = clish_plugin_add_sym(this, func, name)))
+	if (!(s = clish_plugin_add_generic(this, func,
+		name, CLISH_SYM_TYPE_ACTION, BOOL_FALSE)))
 		return s;
 	clish_sym__set_api(s, CLISH_SYM_API_STDOUT);
 
@@ -252,11 +253,12 @@ clish_sym_t *clish_plugin_add_osym(clish_plugin_t *this,
 /*--------------------------------------------------------- */
 /* Add permanent symbol (can't be turned off by dry-run) */
 clish_sym_t *clish_plugin_add_posym(clish_plugin_t *this,
-	clish_hook_action_fn_t *func, const char *name)
+	clish_hook_oaction_fn_t *func, const char *name)
 {
 	clish_sym_t *s;
 
-	if (!(s = clish_plugin_add_psym(this, func, name)))
+	if (!(s = clish_plugin_add_generic(this, func,
+		name, CLISH_SYM_TYPE_ACTION, BOOL_TRUE)))
 		return s;
 	clish_sym__set_api(s, CLISH_SYM_API_STDOUT);
 

+ 86 - 3
clish/shell/shell_execute.c

@@ -14,6 +14,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/file.h>
+#include <sys/wait.h>
 #include <signal.h>
 #include <fcntl.h>
 
@@ -202,6 +203,80 @@ error:
 	return result;
 }
 
+/*----------------------------------------------------------- */
+/* Execute oaction. It suppose the forked process to get
+ * script's stdout. Then forked process write the output back
+ * to klish.
+ */
+static int clish_shell_exec_oaction(clish_hook_oaction_fn_t func,
+	void *context, const char *script, char **out)
+{
+	int result = -1;
+	int real_stdout; /* Saved stdout handler */
+	int pipe1[2], pipe2[2];
+	pid_t cpid = -1;
+	konf_buf_t *buf;
+
+	if (pipe(pipe1))
+		return -1;
+	if (pipe(pipe2))
+		goto stdout_error;
+
+	/* Create process to read script's stdout */
+	cpid = fork();
+	if (cpid == -1) {
+		fprintf(stderr, "Error: Can't fork the stdout-grabber process.\n"
+			"Error: The ACTION will be not executed.\n");
+		goto stdout_error;
+	}
+
+	/* Child: read action's stdout */
+	if (cpid == 0) {
+		char *str;
+		int len;
+
+		close(pipe1[1]);
+		close(pipe2[0]);
+		/* Read the result of script execution */
+		buf = konf_buf_new(pipe1[0]);
+		while (konf_buf_read(buf) > 0);
+		close(pipe1[0]);
+		len = konf_buf__get_len(buf);
+		str = konf_buf__get_buf(buf);
+		write(pipe2[1], str, len);
+		close(pipe2[1]);
+		konf_buf_delete(buf);
+		_exit(0);
+	}
+
+	real_stdout = dup(STDOUT_FILENO);
+	dup2(pipe1[1], STDOUT_FILENO);
+	close(pipe1[0]);
+	close(pipe1[1]);
+	close(pipe2[1]);
+
+	result = func(context, script);
+
+	/* Restore real stdout */
+	dup2(real_stdout, STDOUT_FILENO);
+	close(real_stdout);
+	/* Read the result of script execution */
+	buf = konf_buf_new(pipe2[0]);
+	while (konf_buf_read(buf) > 0);
+	*out = konf_buf__dup_line(buf);
+	konf_buf_delete(buf);
+	close(pipe2[0]);
+	/* Wait for the stdout-grabber process */
+	waitpid(cpid, NULL, 0);
+
+	return result;
+
+stdout_error:
+	close(pipe1[0]);
+	close(pipe1[1]);
+	return -1;
+}
+
 /*----------------------------------------------------------- */
 int clish_shell_exec_action(clish_context_t *context, char **out)
 {
@@ -223,10 +298,18 @@ int clish_shell_exec_action(clish_context_t *context, char **out)
 	script = clish_shell_expand(clish_action__get_script(action), SHELL_VAR_ACTION, context);
 
 	/* Find out the function API */
-	if (clish_sym__get_api(sym) == CLISH_SYM_API_STDOUT) {
-		result = ((clish_hook_oaction_fn_t *)func)(context, script);
-	} else { /* CLISH_SYM_API_SIMPLE */
+	/* 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);
 	}
 
 	lub_string_free(script);

+ 1 - 0
konf/buf.h

@@ -43,6 +43,7 @@ int konf_buf_lseek(konf_buf_t *instance, int newpos);
 int konf_buf__get_fd(const konf_buf_t *instance);
 int konf_buf__get_len(const konf_buf_t *instance);
 char * konf_buf__dup_line(const konf_buf_t *instance);
+char * konf_buf__get_buf(const konf_buf_t *instance);
 void * konf_buf__get_data(const konf_buf_t *instance);
 void konf_buf__set_data(konf_buf_t *instance, void *data);
 

+ 6 - 0
konf/buf/buf.c

@@ -239,6 +239,12 @@ char * konf_buf__dup_line(const konf_buf_t *this)
 	return str;
 }
 
+/*--------------------------------------------------------- */
+char * konf_buf__get_buf(const konf_buf_t *this)
+{
+	return this->buf;
+}
+
 /*--------------------------------------------------------- */
 void * konf_buf__get_data(const konf_buf_t *this)
 {

+ 1 - 1
plugins/clish/builtin_init.c

@@ -29,7 +29,7 @@ CLISH_PLUGIN_INIT(clish)
 	clish_plugin_add_psym(plugin, clish_nop, "clish_nop");
 	clish_plugin_add_psym(plugin, clish_wdog, "clish_wdog");
 	clish_plugin_add_psym(plugin, clish_macros, "clish_macros");
-	clish_plugin_add_sym(plugin, clish_script, "clish_script");
+	clish_plugin_add_osym(plugin, clish_script, "clish_script");
 
 	clish_shell = clish_shell; /* Happy compiler */
 

+ 1 - 1
plugins/clish/private.h

@@ -19,5 +19,5 @@ CLISH_PLUGIN_SYM(clish_history);
 CLISH_PLUGIN_SYM(clish_nested_up);
 CLISH_PLUGIN_SYM(clish_nop);
 CLISH_PLUGIN_SYM(clish_wdog);
-CLISH_PLUGIN_SYM(clish_script);
+CLISH_PLUGIN_OSYM(clish_script);
 CLISH_PLUGIN_SYM(clish_macros);

+ 24 - 53
plugins/clish/sym_script.c

@@ -21,7 +21,7 @@
 #include <fcntl.h>
 
 /*--------------------------------------------------------- */
-CLISH_PLUGIN_SYM(clish_script)
+CLISH_PLUGIN_OSYM(clish_script)
 {
 	clish_shell_t *this = clish_context__get_shell(clish_context);
 	const clish_action_t *action = clish_context__get_action(clish_context);
@@ -29,10 +29,8 @@ CLISH_PLUGIN_SYM(clish_script)
 	pid_t cpid = -1;
 	int res;
 	const char *fifo_name;
-	FILE *rpipe, *wpipe;
+	FILE *wpipe;
 	char *command = NULL;
-
-	/* Signal vars */
 	struct sigaction sig_old_int;
 	struct sigaction sig_old_quit;
 	struct sigaction sig_new;
@@ -86,53 +84,28 @@ CLISH_PLUGIN_SYM(clish_script)
 	lub_string_cat(&command, " ");
 	lub_string_cat(&command, fifo_name);
 
-	/* If the stdout of script is needed */
-	if (out) {
-		konf_buf_t *buf;
-
-		/* Ignore SIGINT and SIGQUIT */
-		sigemptyset(&sig_set);
-		sig_new.sa_flags = 0;
-		sig_new.sa_mask = sig_set;
-		sig_new.sa_handler = SIG_IGN;
-		sigaction(SIGINT, &sig_new, &sig_old_int);
-		sigaction(SIGQUIT, &sig_new, &sig_old_quit);
-
-		/* Execute shebang with FIFO as argument */
-		rpipe = popen(command, "r");
-		if (!rpipe) {
-			fprintf(stderr, "Error: Can't fork the script.\n"
-				"Error: The ACTION will be not executed.\n");
-			lub_string_free(command);
-			kill(cpid, SIGTERM);
-			waitpid(cpid, NULL, 0);
-
-			/* Restore SIGINT and SIGQUIT */
-			sigaction(SIGINT, &sig_old_int, NULL);
-			sigaction(SIGQUIT, &sig_old_quit, NULL);
-
-			return -1;
-		}
-		/* Read the result of script execution */
-		buf = konf_buf_new(fileno(rpipe));
-		while (konf_buf_read(buf) > 0);
-		*out = konf_buf__dup_line(buf);
-		konf_buf_delete(buf);
-		/* Wait for the writing process */
-		kill(cpid, SIGTERM);
-		waitpid(cpid, NULL, 0);
-		/* Wait for script */
-		res = pclose(rpipe);
-
-		/* Restore SIGINT and SIGQUIT */
-		sigaction(SIGINT, &sig_old_int, NULL);
-		sigaction(SIGQUIT, &sig_old_quit, NULL);
-	} else {
-		res = system(command);
-		/* Wait for the writing process */
-		kill(cpid, SIGTERM);
-		waitpid(cpid, NULL, 0);
-	}
+	/* Ignore SIGINT and SIGQUIT */
+	/* Probably this code is necessary to don't get SIGINT
+	 * from executed script. Because the executed script
+	 * and klish have the same terminal.
+	 */
+	sigemptyset(&sig_set);
+	sig_new.sa_flags = 0;
+	sig_new.sa_mask = sig_set;
+	sig_new.sa_handler = SIG_IGN;
+	sigaction(SIGINT, &sig_new, &sig_old_int);
+	sigaction(SIGQUIT, &sig_new, &sig_old_quit);
+
+	res = system(command);
+
+	/* Restore SIGINT and SIGQUIT */
+	sigaction(SIGINT, &sig_old_int, NULL);
+	sigaction(SIGQUIT, &sig_old_quit, NULL);
+
+	/* Wait for the writing process */
+	kill(cpid, SIGTERM);
+	waitpid(cpid, NULL, 0);
+
 	lub_string_free(command);
 
 #ifdef DEBUG
@@ -140,5 +113,3 @@ CLISH_PLUGIN_SYM(clish_script)
 #endif /* DEBUG */
 	return WEXITSTATUS(res);
 }
-
-/*--------------------------------------------------------- */