Browse Source

Create unique FIFO for shebang emulation.

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

+ 39 - 16
clish/clish_script_callback.c

@@ -21,15 +21,15 @@
 #define KLISH_FIFO "/tmp/klish.fifo"
 
 /*--------------------------------------------------------- */
-bool_t clish_script_callback(const clish_shell_t * this,
+bool_t clish_script_callback(clish_shell_t * this,
 	const clish_command_t * cmd, const char *script)
 {
 	const char * shebang = NULL;
 	pid_t cpid;
 	char buf;
 	int res;
-	const char *fifo_name = KLISH_FIFO;
-	FILE *rpipe;
+	const char *fifo_name;
+	FILE *rpipe, *wpipe;
 	char *command = NULL;
 
 	/* Signal vars */
@@ -43,35 +43,36 @@ bool_t clish_script_callback(const clish_shell_t * this,
 	if (!script) /* Nothing to do */
 		return BOOL_TRUE;
 
+	/* Find out shebang */
 	shebang = clish_command__get_shebang(cmd);
 	if (!shebang)
 		shebang = clish_shell__get_default_shebang(this);
 	assert(shebang);
+
 #ifdef DEBUG
 	fprintf(stderr, "SHEBANG: #!%s\n", shebang);
 	fprintf(stderr, "SCRIPT: %s\n", script);
 #endif /* DEBUG */
 
-	mkfifo(fifo_name, 0600);
-
-	/* 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);
+	/* Get FIFO */
+	fifo_name = clish_shell__get_fifo(this);
+	if (!fifo_name) {
+		fprintf(stderr, "System error. Can't create temporary FIFO.\n"
+			"The ACTION will be not executed.\n");
+		return BOOL_FALSE;
+	}
 
 	/* Create process to execute script */
 	cpid = fork();
 	if (cpid == -1) {
+		fprintf(stderr, "System error. Can't fork the write process.\n"
+			"The ACTION will be not executed.\n");
 		return BOOL_FALSE;
 	}
 
 	/* Child */
 	if (cpid == 0) {
 		int retval;
-		FILE *wpipe;
 		wpipe = fopen(fifo_name, "w");
 		if (!wpipe)
 			_exit(-1);
@@ -81,19 +82,41 @@ bool_t clish_script_callback(const clish_shell_t * this,
 	}
 
 	/* Parent */
+	/* 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);
+
+	/* Prepare command */
 	lub_string_cat(&command, shebang);
 	lub_string_cat(&command, " ");
 	lub_string_cat(&command, fifo_name);
 
+	/* Execute shebang with FIFO as argument */
 	rpipe = popen(command, "r");
 	lub_string_free(command);
+	if (!rpipe) {
+		fprintf(stderr, "System error. Can't fork the script.\n"
+			"The ACTION will be not executed.\n");
+		kill(cpid, SIGTERM);
+		waitpid(cpid, NULL, 0);
+
+		/* Restore SIGINT and SIGQUIT */
+		sigaction(SIGINT, &sig_old_int, NULL);
+		sigaction(SIGQUIT, &sig_old_quit, NULL);
+
+		return BOOL_FALSE;
+	}
 	/* Read the result of script execution */
 	while (read(fileno(rpipe), &buf, 1) > 0)
 		write(fileno(clish_shell__get_ostream(this)), &buf, 1);
-	/* Wait for script */
-	res = pclose(rpipe);
 	/* Wait for the writing process */
 	waitpid(cpid, NULL, 0);
+	/* Wait for script */
+	res = pclose(rpipe);
 
 	/* Restore SIGINT and SIGQUIT */
 	sigaction(SIGINT, &sig_old_int, NULL);
@@ -106,7 +129,7 @@ bool_t clish_script_callback(const clish_shell_t * this,
 }
 
 /*--------------------------------------------------------- */
-bool_t clish_dryrun_callback(const clish_shell_t * this,
+bool_t clish_dryrun_callback(clish_shell_t * this,
 	const clish_command_t * cmd, const char *script)
 {
 #ifdef DEBUG

+ 2 - 1
clish/shell.h

@@ -137,7 +137,7 @@ typedef bool_t clish_shell_script_fn_t(
 	/** 
          * The shell instance which invoked this call
          */
-					      const clish_shell_t * instance,
+					clish_shell_t * instance,
 	/** 
          * The command which invoked this call
          */
@@ -384,6 +384,7 @@ char * clish_shell__expand_text(const clish_shell_t *instance,
 	clish_command_t *cmd, clish_pargv_t *pargv, const char *text);
 char * clish_shell__expand_variable(const clish_shell_t *instance,
 	clish_command_t *cmd, clish_pargv_t *pargv, const char *var);
+const char * clish_shell__get_fifo(clish_shell_t * instance);
 
 _END_C_DECL
 

+ 1 - 0
clish/shell/private.h

@@ -67,6 +67,7 @@ struct clish_shell_s {
 	pthread_t pthread;
 	clish_context_t context;
 	char * default_shebang;
+	char * fifo_name; /* The name of temporary fifo file */
 };
 
 /**

+ 4 - 0
clish/shell/shell_delete.c

@@ -62,6 +62,10 @@ static void clish_shell_fini(clish_shell_t * this)
 
 	lub_string_free(this->lockfile);
 	lub_string_free(this->default_shebang);
+	if (this->fifo_name) {
+		unlink(this->fifo_name);
+		lub_string_free(this->fifo_name);
+	}
 
 	/* Clear the context */
 	if (this->context.completion_pargv) {

+ 27 - 0
clish/shell/shell_execute.c

@@ -355,3 +355,30 @@ static bool_t clish_nested_up(const clish_shell_t * shell, const lub_argv_t * ar
 }
 
 /*----------------------------------------------------------- */
+const char * clish_shell__get_fifo(clish_shell_t * this)
+{
+	char *name;
+	int res;
+
+	if (this->fifo_name) {
+		if (0 == access(this->fifo_name, R_OK | W_OK))
+			return this->fifo_name;
+		unlink(this->fifo_name);
+		lub_string_free(this->fifo_name);
+		this->fifo_name = NULL;
+	}
+
+	do {
+		char template[] = "/tmp/klish.fifo.XXXXXX";
+		name = mktemp(template);
+		if (name[0] == '\0')
+			return NULL;
+		res = mkfifo(name, 0600);
+		if (res == 0)
+			this->fifo_name = lub_string_dup(name);
+	} while ((res < 0) && (EEXIST == errno));
+
+	return this->fifo_name;
+}
+
+/*----------------------------------------------------------- */

+ 1 - 0
clish/shell/shell_new.c

@@ -46,6 +46,7 @@ clish_shell_init(clish_shell_t * this,
 	this->client = NULL;
 	this->lockfile = lub_string_dup(CLISH_LOCK_PATH);
 	this->default_shebang = lub_string_dup("/bin/sh");
+	this->fifo_name = NULL;
 
 	/* Create internal ptypes and params */
 	/* Current depth */