Browse Source

ksession: Initial version of ksession_exec_locally()

Serj Kalichev 2 years ago
parent
commit
db6cac8ef5
5 changed files with 96 additions and 3 deletions
  1. 1 0
      klish/kexec.h
  2. 7 0
      klish/ksession.h
  3. 2 2
      klish/ksession/kexec.c
  4. 76 0
      klish/ksession/ksession.c
  5. 10 1
      klish/ktp/ktpd_session.c

+ 1 - 0
klish/kexec.h

@@ -41,6 +41,7 @@ bool_t kexec_contexts_is_empty(const kexec_t *exec);
 kexec_contexts_node_t *kexec_contexts_iter(const kexec_t *exec);
 kcontext_t *kexec_contexts_each(kexec_contexts_node_t **iter);
 
+bool_t kexec_continue_command_execution(kexec_t *exec, pid_t pid, int wstatus);
 bool_t kexec_exec(kexec_t *exec);
 
 

+ 7 - 0
klish/ksession.h

@@ -24,6 +24,10 @@ void ksession_free(ksession_t *session);
 const kscheme_t *ksession_scheme(const ksession_t *session);
 kpath_t *ksession_path(const ksession_t *session);
 
+// Done
+bool_t ksession_done(const ksession_t *session);
+bool_t ksession_set_done(ksession_t *session, bool_t done);
+
 kpargv_t *ksession_parse_line(ksession_t *session, const faux_argv_t *argv,
 	kpargv_purpose_e purpose);
 faux_list_t *ksession_split_pipes(const char *raw_line, faux_error_t *error);
@@ -32,6 +36,9 @@ kpargv_t *ksession_parse_for_completion(ksession_t *session,
 kexec_t *ksession_parse_for_exec(ksession_t *session, const char *raw_line,
 	faux_error_t *error);
 
+bool_t ksession_exec_locally(ksession_t *session, const char *line,
+	int *retcode, faux_error_t *error);
+
 
 C_DECL_END
 

+ 2 - 2
klish/ksession/kexec.c

@@ -326,7 +326,7 @@ static bool_t exec_action_sequence(const kexec_t *exec, kcontext_t *context,
 }
 
 
-static bool_t continue_command_execution(kexec_t *exec, pid_t pid, int wstatus)
+bool_t kexec_continue_command_execution(kexec_t *exec, pid_t pid, int wstatus)
 {
 	faux_list_node_t *iter = NULL;
 	kcontext_t *context = NULL;
@@ -360,7 +360,7 @@ bool_t kexec_exec(kexec_t *exec)
 
 	// Here no ACTIONs are executing, so pass -1 as pid of terminated
 	// ACTION's process.
-	continue_command_execution(exec, -1, 0);
+	kexec_continue_command_execution(exec, -1, 0);
 
 	return BOOL_TRUE;
 }

+ 76 - 0
klish/ksession/ksession.c

@@ -4,8 +4,12 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
 #include <faux/argv.h>
+#include <faux/eloop.h>
 #include <klish/khelper.h>
 #include <klish/kview.h>
 #include <klish/kscheme.h>
@@ -18,6 +22,7 @@
 struct ksession_s {
 	const kscheme_t *scheme;
 	kpath_t *path;
+	bool_t done; // Indicates that session is over and must be closed
 };
 
 
@@ -27,6 +32,10 @@ KGET(session, const kscheme_t *, scheme);
 // Path
 KGET(session, kpath_t *, path);
 
+// Done
+KGET_BOOL(session, done);
+KSET_BOOL(session, done);
+
 
 ksession_t *ksession_new(const kscheme_t *scheme, const char *start_entry)
 {
@@ -66,6 +75,7 @@ ksession_t *ksession_new(const kscheme_t *scheme, const char *start_entry)
 	level = klevel_new(entry);
 	assert(level);
 	kpath_push(session->path, level);
+	session->done = BOOL_FALSE;
 
 	return session;
 }
@@ -82,10 +92,57 @@ void ksession_free(ksession_t *session)
 }
 
 
+static bool_t stop_loop_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
+	void *associated_data, void *user_data)
+{
+	ksession_t *session = (ksession_t *)user_data;
+
+	if (!session)
+		return BOOL_FALSE;
+
+	ksession_set_done(session, BOOL_TRUE); // Stop the whole session
+
+	// Happy compiler
+	eloop = eloop;
+	type = type;
+	associated_data = associated_data;
+
+	return BOOL_FALSE; // Stop Event Loop
+}
+
+
+static bool_t action_terminated_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
+	void *associated_data, void *user_data)
+{
+	int wstatus = 0;
+	pid_t child_pid = -1;
+	kexec_t *exec = (kexec_t *)user_data;
+
+	if (!exec)
+		return BOOL_FALSE;
+
+	// Wait for any child process. Doesn't block.
+	while ((child_pid = waitpid(-1, &wstatus, WNOHANG)) > 0)
+		kexec_continue_command_execution(exec, child_pid, wstatus);
+
+	// Check if kexec is done now
+	if (kexec_done(exec))
+		return BOOL_FALSE; // To break a loop
+
+	// Happy compiler
+	eloop = eloop;
+	type = type;
+	associated_data = associated_data;
+
+	return BOOL_TRUE;
+}
+
+
 bool_t ksession_exec_locally(ksession_t *session, const char *line,
 	int *retcode, faux_error_t *error)
 {
 	kexec_t *exec = NULL;
+	faux_eloop_t *eloop = NULL;
 
 	assert(session);
 	if (!session)
@@ -96,8 +153,27 @@ bool_t ksession_exec_locally(ksession_t *session, const char *line,
 	if (!exec)
 		return BOOL_FALSE;
 
+	// Session status can be changed while parsing because it can execute
+	// nested ksession_exec_locally() to check for PTYPEs, CONDitions etc.
+	// So check for 'done' flag to propagate it.
+	if (ksession_done(session))
+		return BOOL_FALSE; // Because action is not completed
+
+	// Execute kexec and then wait for completion using local Eloop
 	if (!kexec_exec(exec))
 		return BOOL_FALSE; // Something went wrong
+	// If kexec contains only sync ACTIONs then we don't need event loop
+	// and can return here.
+	if (kexec_retcode(exec, retcode))
+		return BOOL_TRUE;
+
+	// Local service loop
+	faux_eloop_add_signal(eloop, SIGINT, stop_loop_ev, session);
+	faux_eloop_add_signal(eloop, SIGTERM, stop_loop_ev, session);
+	faux_eloop_add_signal(eloop, SIGQUIT, stop_loop_ev, session);
+	faux_eloop_add_signal(eloop, SIGCHLD, action_terminated_ev, exec);
+	faux_eloop_loop(eloop);
+	faux_eloop_free(eloop);
 
 	kexec_retcode(exec, retcode);
 

+ 10 - 1
klish/ktp/ktpd_session.c

@@ -160,7 +160,7 @@ static bool_t ktpd_session_process_cmd(ktpd_session_t *session, faux_msg_t *msg)
 	}
 
 	// Parsing
-	error = faux_error_new();
+/*	error = faux_error_new();
 	exec = ksession_parse_for_exec(session->ksession, line, error);
 	faux_str_free(line);
 
@@ -178,7 +178,16 @@ static bool_t ktpd_session_process_cmd(ktpd_session_t *session, faux_msg_t *msg)
 	}
 
 	kexec_exec(exec);
+*/
 
+	{
+	int retcode = 0;
+	bool_t r = BOOL_FALSE;
+	r = ksession_exec_locally(session->ksession, line, &retcode, error);
+	if (!r)
+		printf("ksession_exec_locally() return value is false\n");
+	printf("kexec retcode is %d\n", retcode);
+	}
 
 //	ktpd_session_exec(session, exec);