Browse Source

Unfinished 'silent' sym processing

Serj Kalichev 5 months ago
parent
commit
b32ebd13e9

+ 13 - 0
klish/kcontext.h

@@ -7,6 +7,7 @@
 #define _klish_kcontext_h
 
 #include <faux/list.h>
+#include <faux/buf.h>
 #include <klish/kcontext_base.h>
 #include <klish/kpargv.h>
 #include <klish/kscheme.h>
@@ -72,6 +73,14 @@ FAUX_HIDDEN bool_t kcontext_set_stdout(kcontext_t *context, int stdout);
 int kcontext_stderr(const kcontext_t *context);
 FAUX_HIDDEN bool_t kcontext_set_stderr(kcontext_t *context, int stderr);
 
+// bufout
+faux_buf_t *kcontext_bufout(const kcontext_t *context);
+FAUX_HIDDEN bool_t kcontext_set_bufout(kcontext_t *context, faux_buf_t *bufout);
+
+// buferr
+faux_buf_t *kcontext_buferr(const kcontext_t *context);
+FAUX_HIDDEN bool_t kcontext_set_buferr(kcontext_t *context, faux_buf_t *buferr);
+
 // PID
 pid_t kcontext_pid(const kcontext_t *context);
 FAUX_HIDDEN bool_t kcontext_set_pid(kcontext_t *context, pid_t pid);
@@ -92,6 +101,10 @@ bool_t kcontext_set_line(kcontext_t *exec, const char *line);
 size_t kcontext_pipeline_stage(const kcontext_t *context);
 FAUX_HIDDEN bool_t kcontext_set_pipeline_stage(kcontext_t *context, size_t pipeline_stage);
 
+// Is last pipeline stage
+bool_t kcontext_is_last_pipeline_stage(const kcontext_t *context);
+FAUX_HIDDEN bool_t kcontext_set_is_last_pipeline_stage(kcontext_t *context, bool_t is_last_pipeline_stage);
+
 // Wrappers
 kparg_t *kcontext_candidate_parg(const kcontext_t *context);
 const kentry_t *kcontext_candidate_entry(const kcontext_t *context);

+ 18 - 0
klish/ksession/kcontext.c

@@ -33,10 +33,13 @@ struct kcontext_s {
 	int stdin;
 	int stdout;
 	int stderr;
+	faux_buf_t *bufout; // Don't free. Just a link
+	faux_buf_t *buferr; // Don't free. Just a link
 	pid_t pid;
 	bool_t done; // If all actions are done
 	char *line; // Text command context belong to
 	size_t pipeline_stage; // Index of current command within full pipeline
+	bool_t is_last_pipeline_stage;
 };
 
 
@@ -93,6 +96,14 @@ FAUX_HIDDEN KSET(context, int, stdout);
 KGET(context, int, stderr);
 FAUX_HIDDEN KSET(context, int, stderr);
 
+// bufout
+KGET(context, faux_buf_t *, bufout);
+FAUX_HIDDEN KSET(context, faux_buf_t *, bufout);
+
+// buferr
+KGET(context, faux_buf_t *, buferr);
+FAUX_HIDDEN KSET(context, faux_buf_t *, buferr);
+
 // PID
 KGET(context, pid_t, pid);
 FAUX_HIDDEN KSET(context, pid_t, pid);
@@ -113,6 +124,10 @@ FAUX_HIDDEN KSET_STR(context, line);
 KGET(context, size_t, pipeline_stage);
 FAUX_HIDDEN KSET(context, size_t, pipeline_stage);
 
+// Is last pipeline stage
+KGET(context, bool_t, is_last_pipeline_stage);
+FAUX_HIDDEN KSET(context, bool_t, is_last_pipeline_stage);
+
 
 kcontext_t *kcontext_new(kcontext_type_e type)
 {
@@ -137,11 +152,14 @@ kcontext_t *kcontext_new(kcontext_type_e type)
 	context->stdin = -1;
 	context->stdout = -1;
 	context->stderr = -1;
+	context->bufout = NULL;
+	context->buferr = NULL;
 	context->pid = -1; // PID of currently executed ACTION
 	context->session = NULL; // Don't free
 	context->done = BOOL_FALSE;
 	context->line = NULL;
 	context->pipeline_stage = 0;
+	context->is_last_pipeline_stage = BOOL_TRUE;
 
 	return context;
 }

+ 14 - 1
klish/ksession/kexec.c

@@ -462,6 +462,20 @@ static bool_t exec_action_sync(const kexec_t *exec, kcontext_t *context,
 	pid_t child_pid = -1;
 	int pipe_stdout[2] = {};
 	int pipe_stderr[2] = {};
+	ksym_t *sym = NULL;
+
+	sym = kaction_sym(action);
+	fn = ksym_function(kaction_sym(action));
+
+	// Execute silent sync function and continue
+	// Only last in pipeline stage can be silent because last stage
+	// has bufout
+	if (ksym_silent(sym) && kcontext_is_last_pipeline_stage(context)) {
+		exitcode = fn(context);
+		if (retcode)
+			*retcode = exitcode;
+		return BOOL_TRUE;
+	}
 
 	// Create pipes beetween sym function and grabber
 	if (pipe(pipe_stdout) < 0)
@@ -472,7 +486,6 @@ static bool_t exec_action_sync(const kexec_t *exec, kcontext_t *context,
 		return BOOL_FALSE;
 	}
 
-	fn = ksym_function(kaction_sym(action));
 
 	// Prepare streams before fork
 	fflush(stdout);

+ 20 - 17
klish/ksession/ksession_parse.c

@@ -611,6 +611,7 @@ kexec_t *ksession_parse_for_exec(ksession_t *session, const char *raw_line,
 		faux_argv_t *argv = (faux_argv_t *)faux_list_data(iter);
 		kcontext_t *context = NULL;
 		bool_t is_first = (iter == faux_list_head(split));
+		bool_t is_last = (iter == faux_list_tail(split));
 		char *context_line = NULL;
 
 		pargv = ksession_parse_line(session, argv, KPURPOSE_EXEC, !is_first);
@@ -633,6 +634,11 @@ kexec_t *ksession_parse_for_exec(ksession_t *session, const char *raw_line,
 		kcontext_set_line(context, context_line);
 		faux_str_free(context_line);
 		kcontext_set_pipeline_stage(context, index);
+		kcontext_set_is_last_pipeline_stage(context, is_last);
+		if (is_last) {
+			kcontext_set_bufout(context, kexec_bufout(exec));
+			kcontext_set_buferr(context, kexec_buferr(exec));
+		}
 		kexec_add_contexts(exec, context);
 
 		// Next component
@@ -695,6 +701,7 @@ kexec_t *ksession_parse_for_local_exec(ksession_t *session, const kentry_t *entr
 	kcontext_set_parent_pargv(context, parent_pargv);
 	kcontext_set_parent_context(context, parent_context);
 	kcontext_set_parent_exec(context, parent_exec);
+	kcontext_set_bufout(context, kexec_bufout(exec));
 	kcontext_set_session(context, session);
 	kexec_add_contexts(exec, context);
 
@@ -833,25 +840,21 @@ bool_t ksession_exec_locally(ksession_t *session, const kentry_t *entry,
 		return BOOL_FALSE; // Something went wrong
 	}
 	// If kexec contains only non-exec (for example dry-run) ACTIONs then
-	// we don't need event loop and can return here.
-	if (kexec_retcode(exec, retcode)) {
-		kexec_free(exec);
-		return BOOL_TRUE;
+	// we don't need event loop
+	if (!kexec_retcode(exec, retcode)) {
+		// Local service loop
+		eloop = faux_eloop_new(NULL);
+		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_add_fd(eloop, kexec_stdout(exec), POLLIN,
+			action_stdout_ev, exec);
+		faux_eloop_loop(eloop);
+		faux_eloop_free(eloop);
+		kexec_retcode(exec, retcode);
 	}
 
-	// Local service loop
-	eloop = faux_eloop_new(NULL);
-	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_add_fd(eloop, kexec_stdout(exec), POLLIN,
-		action_stdout_ev, exec);
-	faux_eloop_loop(eloop);
-	faux_eloop_free(eloop);
-
-	kexec_retcode(exec, retcode);
-
 	if (!out) {
 		kexec_free(exec);
 		return BOOL_TRUE;

+ 27 - 21
klish/ktp/ktpd_session.c

@@ -64,7 +64,7 @@ static bool_t action_stdout_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
 	void *associated_data, void *user_data);
 static bool_t action_stderr_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
 	void *associated_data, void *user_data);
-static bool_t get_stream(ktpd_session_t *ktpd, int fd, bool_t is_stderr,
+static bool_t get_stream(ktpd_session_t *ktpd, kexec_t *exec, int fd, bool_t is_stderr,
 	bool_t process_all_data);
 
 
@@ -493,6 +493,9 @@ static bool_t ktpd_session_exec(ktpd_session_t *ktpd, const char *line,
 			*view_was_changed_p = !kpath_is_equal(
 				ksession_path(ktpd->session),
 				kexec_saved_path(exec));
+		// 'Silent' sym can write directly to stdout/stderr buffer
+		get_stream(ktpd, exec, -1, BOOL_FALSE, BOOL_TRUE);
+		get_stream(ktpd, exec, -1, BOOL_TRUE, BOOL_TRUE);
 		ktpd_session_log(ktpd, exec);
 		kexec_free(exec);
 		return BOOL_TRUE;
@@ -550,8 +553,8 @@ static bool_t wait_for_actions_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
 	// Sometimes SIGCHILD signal can appear before all data were really read
 	// from process stdout buffer. So read the least data before closing
 	// file descriptors and send it to client.
-	get_stream(ktpd, kexec_stdout(ktpd->exec), BOOL_FALSE, BOOL_TRUE);
-	get_stream(ktpd, kexec_stderr(ktpd->exec), BOOL_TRUE, BOOL_TRUE);
+	get_stream(ktpd, ktpd->exec, kexec_stdout(ktpd->exec), BOOL_FALSE, BOOL_TRUE);
+	get_stream(ktpd, ktpd->exec, kexec_stderr(ktpd->exec), BOOL_TRUE, BOOL_TRUE);
 	faux_eloop_del_fd(eloop, kexec_stdin(ktpd->exec));
 	faux_eloop_del_fd(eloop, kexec_stdout(ktpd->exec));
 	faux_eloop_del_fd(eloop, kexec_stderr(ktpd->exec));
@@ -1380,7 +1383,7 @@ int ktpd_session_fd(const ktpd_session_t *ktpd)
 }
 
 
-static bool_t get_stream(ktpd_session_t *ktpd, int fd, bool_t is_stderr,
+static bool_t get_stream(ktpd_session_t *ktpd, kexec_t *exec, int fd, bool_t is_stderr,
 	bool_t process_all_data)
 {
 	ssize_t r = -1;
@@ -1391,27 +1394,30 @@ static bool_t get_stream(ktpd_session_t *ktpd, int fd, bool_t is_stderr,
 
 	if (!ktpd)
 		return BOOL_TRUE;
-	if (!ktpd->exec)
+	if (!exec)
 		return BOOL_TRUE;
 
 	if (is_stderr)
-		faux_buf = kexec_buferr(ktpd->exec);
+		faux_buf = kexec_buferr(exec);
 	else
-		faux_buf = kexec_bufout(ktpd->exec);
+		faux_buf = kexec_bufout(exec);
 	assert(faux_buf);
 
-	do {
-		void *linear_buf = NULL;
-		ssize_t really_readed = 0;
-		ssize_t linear_len =
-			faux_buf_dwrite_lock_easy(faux_buf, &linear_buf);
-		// Non-blocked read. The fd became non-blocked while
-		// kexec_prepare().
-		r = read(fd, linear_buf, linear_len);
-		if (r > 0)
-			really_readed = r;
-		faux_buf_dwrite_unlock_easy(faux_buf, really_readed);
-	} while ((r > 0) && process_all_data);
+	// Don't read stream if fd == -1
+	if (fd >= 0) {
+		do {
+			void *linear_buf = NULL;
+			ssize_t really_readed = 0;
+			ssize_t linear_len =
+				faux_buf_dwrite_lock_easy(faux_buf, &linear_buf);
+			// Non-blocked read. The fd became non-blocked while
+			// kexec_prepare().
+			r = read(fd, linear_buf, linear_len);
+			if (r > 0)
+				really_readed = r;
+			faux_buf_dwrite_unlock_easy(faux_buf, really_readed);
+		} while ((r > 0) && process_all_data);
+	}
 
 	len = faux_buf_len(faux_buf);
 	if (0 == len)
@@ -1450,7 +1456,7 @@ static bool_t action_stdout_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
 		push_stdin(ktpd);
 
 	if (info->revents & POLLIN)
-		get_stream(ktpd, info->fd, BOOL_FALSE, BOOL_FALSE);
+		get_stream(ktpd, ktpd->exec, info->fd, BOOL_FALSE, BOOL_FALSE);
 
 	// Some errors or fd is closed so remove it from polling
 	// EOF || POLERR || POLLNVAL
@@ -1470,7 +1476,7 @@ static bool_t action_stderr_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
 	ktpd_session_t *ktpd = (ktpd_session_t *)user_data;
 
 	if (info->revents & POLLIN)
-		get_stream(ktpd, info->fd, BOOL_TRUE, BOOL_FALSE);
+		get_stream(ktpd, ktpd->exec, info->fd, BOOL_TRUE, BOOL_FALSE);
 
 	// Some errors or fd is closed so remove it from polling
 	// EOF || POLERR || POLLNVAL

+ 22 - 0
plugins/klish/misc.c

@@ -152,3 +152,25 @@ int klish_prompt(kcontext_t *context)
 
 	return 0;
 }
+
+
+int klish_silent_test(kcontext_t *context)
+{
+	const char *script = NULL;
+	char *str = NULL;
+	faux_buf_t *bufout = kcontext_bufout(context);
+
+	script = kcontext_script(context);
+	if (faux_str_is_empty(script))
+		script = "";
+
+	str = faux_str_sprintf("%s\n", script);
+
+	if (bufout)
+		faux_buf_write(kcontext_bufout(context), str, strlen(str));
+	else
+		printf("%s", str);
+	faux_str_free(str);
+
+	return 0;
+}

+ 4 - 2
plugins/klish/plugin_init.c

@@ -34,6 +34,8 @@ int kplugin_klish_init(kcontext_t *context)
 	kplugin_add_syms(plugin, ksym_new_ext("pwd", klish_pwd,
 		KSYM_PERMANENT, KSYM_SYNC, KSYM_NONSILENT));
 	kplugin_add_syms(plugin, ksym_new("prompt", klish_prompt));
+kplugin_add_syms(plugin, ksym_new_ext("silent-test", klish_silent_test,
+	KSYM_PERMANENT, KSYM_SYNC, KSYM_SILENT));
 
 	// Log
 	kplugin_add_syms(plugin, ksym_new("syslog", klish_syslog));
@@ -49,9 +51,9 @@ int kplugin_klish_init(kcontext_t *context)
 	kplugin_add_syms(plugin, ksym_new_ext("COMMAND", klish_ptype_COMMAND,
 		KSYM_USERDEFINED_PERMANENT, KSYM_SYNC, KSYM_SILENT));
 	kplugin_add_syms(plugin, ksym_new_ext("completion_COMMAND", klish_completion_COMMAND,
-		KSYM_USERDEFINED_PERMANENT, KSYM_SYNC, KSYM_SILENT));
+		KSYM_USERDEFINED_PERMANENT, KSYM_SYNC, KSYM_NONSILENT));
 	kplugin_add_syms(plugin, ksym_new_ext("help_COMMAND", klish_help_COMMAND,
-		KSYM_USERDEFINED_PERMANENT, KSYM_SYNC, KSYM_SILENT));
+		KSYM_USERDEFINED_PERMANENT, KSYM_SYNC, KSYM_NONSILENT));
 	kplugin_add_syms(plugin, ksym_new_ext("COMMAND_CASE", klish_ptype_COMMAND_CASE,
 		KSYM_USERDEFINED_PERMANENT, KSYM_SYNC, KSYM_SILENT));
 	kplugin_add_syms(plugin, ksym_new_ext("INT", klish_ptype_INT,

+ 2 - 0
plugins/klish/private.h

@@ -19,6 +19,8 @@ int klish_printl(kcontext_t *context);
 int klish_pwd(kcontext_t *context);
 int klish_prompt(kcontext_t *context);
 
+int klish_silent_test(kcontext_t *context);
+
 // Log
 int klish_syslog(kcontext_t *context);