Browse Source

klishd: ksession_parse_for_exec()

Serj Kalichev 2 years ago
parent
commit
197a51be43
6 changed files with 118 additions and 30 deletions
  1. 1 1
      bin/klish/klish.c
  2. 1 0
      klish/kpargv.h
  3. 4 1
      klish/ksession.h
  4. 4 0
      klish/ksession/kpargv.c
  5. 88 9
      klish/ksession/ksession_parse.c
  6. 20 19
      klish/ktp/ktpd_session.c

+ 1 - 1
bin/klish/klish.c

@@ -54,7 +54,7 @@ int main(int argc, char **argv)
 	net = faux_net_new();
 	faux_net_set_fd(net, ktp_session_fd(session));
 	msg = faux_msg_new(KTP_MAGIC, KTP_MAJOR, KTP_MINOR);
-	faux_msg_set_cmd(msg, KTP_COMPLETION);
+	faux_msg_set_cmd(msg, KTP_CMD);
 	if (opts->line)
 		faux_msg_add_param(msg, KTP_PARAM_LINE,
 			opts->line, strlen(opts->line));

+ 1 - 0
klish/kpargv.h

@@ -19,6 +19,7 @@ typedef enum {
 	KPARSE_INCOMPLETED,
 	KPARSE_ILLEGAL,
 	KPARSE_ERROR,
+	KPARSE_NOACTION,
 	KPARSE_MAX,
 } kpargv_status_e;
 

+ 4 - 1
klish/ksession.h

@@ -9,6 +9,7 @@
 #include <klish/kscheme.h>
 #include <klish/kpath.h>
 #include <klish/kpargv.h>
+#include <klish/kexec.h>
 
 #define KSESSION_STARTING_ENTRY "main"
 
@@ -25,9 +26,11 @@ kpath_t *ksession_path(const ksession_t *session);
 
 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_list_t *ksession_split_pipes(const char *raw_line, faux_error_t *error);
 kpargv_t *ksession_parse_for_completion(ksession_t *session,
 	const char *raw_line);
+kexec_t *ksession_parse_for_exec(ksession_t *session, const char *raw_line,
+	faux_error_t *error);
 
 
 C_DECL_END

+ 4 - 0
klish/ksession/kpargv.c

@@ -6,6 +6,7 @@
 #include <string.h>
 
 #include <faux/list.h>
+#include <faux/error.h>
 #include <klish/khelper.h>
 #include <klish/kentry.h>
 #include <klish/kpargv.h>
@@ -171,6 +172,9 @@ const char *kpargv_status_decode(kpargv_status_e status)
 	case KPARSE_ILLEGAL:
 		s = "Illegal";
 		break;
+	case KPARSE_NOACTION:
+		s = "Has no action";
+		break;
 	default: // ERROR/MAX/NONE
 		s = "Error";
 		break;

+ 88 - 9
klish/ksession/ksession_parse.c

@@ -5,12 +5,15 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <faux/list.h>
 #include <faux/argv.h>
+#include <faux/error.h>
 #include <klish/khelper.h>
 #include <klish/kview.h>
 #include <klish/kscheme.h>
 #include <klish/kpath.h>
 #include <klish/kpargv.h>
+#include <klish/kexec.h>
 #include <klish/ksession.h>
 
 
@@ -265,7 +268,10 @@ kpargv_t *ksession_parse_line(ksession_t *session, const faux_argv_t *argv,
 		else
 			pstatus = KPARSE_ILLEGAL; // Additional not parsable args
 	} else if (KPARSE_NOTFOUND == pstatus)
-			pstatus = KPARSE_ILLEGAL; // Unknown command
+		pstatus = KPARSE_ILLEGAL; // Unknown command
+	// If no ACTIONs were found i.e. command was not found
+	if ((KPARSE_OK == pstatus) && !kpargv_command(pargv))
+		pstatus = KPARSE_NOACTION;
 
 	kpargv_set_status(pargv, pstatus);
 	kpargv_set_level(pargv, level_found);
@@ -275,7 +281,7 @@ kpargv_t *ksession_parse_line(ksession_t *session, const faux_argv_t *argv,
 
 
 // Delimeter of commands is '|' (pipe)
-faux_list_t *ksession_split_pipes(const char *raw_line)
+faux_list_t *ksession_split_pipes(const char *raw_line, faux_error_t *error)
 {
 	faux_list_t *list = NULL;
 	faux_argv_t *argv = NULL;
@@ -316,6 +322,8 @@ faux_list_t *ksession_split_pipes(const char *raw_line)
 			if (faux_argv_len(cur_argv) == 0) {
 				faux_argv_free(argv);
 				faux_list_free(list);
+				faux_error_sprintf(error, "The pipe '|' can't "
+					"be at the first position");
 				return NULL;
 			}
 			// Add argv to argv's list
@@ -331,12 +339,13 @@ faux_list_t *ksession_split_pipes(const char *raw_line)
 	faux_argv_set_continuable(cur_argv, faux_argv_is_continuable(argv));
 	// Empty cur_argv is not an error. It's usefull for completion and help.
 	// But empty cur_argv and continuable is abnormal.
-	if (faux_argv_len(cur_argv) == 0) {
-		if (faux_argv_is_continuable(cur_argv)) {
-			faux_argv_free(argv);
-			faux_list_free(list);
-			return NULL;
-		}
+	if ((faux_argv_len(cur_argv) == 0) &&
+		faux_argv_is_continuable(cur_argv)) {
+		faux_argv_free(argv);
+		faux_list_free(list);
+		faux_error_sprintf(error, "The pipe '|' can't "
+			"be the last argument");
+		return NULL;
 	}
 	faux_list_add(list, cur_argv);
 
@@ -348,6 +357,8 @@ faux_list_t *ksession_split_pipes(const char *raw_line)
 
 // All components except last one must be legal for execution but last
 // component must be parsed for completion.
+// Completion is a "back-end" operation so it doesn't need detailed error
+// reporting.
 kpargv_t *ksession_parse_for_completion(ksession_t *session,
 	const char *raw_line)
 {
@@ -363,7 +374,7 @@ kpargv_t *ksession_parse_for_completion(ksession_t *session,
 		return NULL;
 
 	// Split raw line (with '|') to components
-	split = ksession_split_pipes(raw_line);
+	split = ksession_split_pipes(raw_line, NULL);
 	if (!split || (faux_list_len(split) < 1)) {
 		faux_list_free(split);
 		return NULL;
@@ -396,3 +407,71 @@ kpargv_t *ksession_parse_for_completion(ksession_t *session,
 
 	return pargv;
 }
+
+
+kexec_t *ksession_parse_for_exec(ksession_t *session, const char *raw_line,
+	faux_error_t *error)
+{
+	faux_list_t *split = NULL;
+	faux_list_node_t *iter = NULL;
+	kpargv_t *pargv = NULL;
+	kexec_t *exec = NULL;
+
+	assert(session);
+	if (!session)
+		return NULL;
+	assert(raw_line);
+	if (!raw_line)
+		return NULL;
+
+	// Split raw line (with '|') to components
+	split = ksession_split_pipes(raw_line, error);
+	if (!split || (faux_list_len(split) < 1)) {
+		faux_list_free(split);
+		return NULL;
+	}
+
+	// Create exec list
+	exec = kexec_new();
+	assert(exec);
+	if (!exec) {
+		faux_list_free(split);
+		return NULL;
+	}
+
+	iter = faux_list_head(split);
+	while (iter) {
+		faux_argv_t *argv = (faux_argv_t *)faux_list_data(iter);
+		pargv = ksession_parse_line(session, argv, KPURPOSE_EXEC);
+		// All components must be ready for execution
+		if (!pargv) {
+			kpargv_free(pargv);
+			faux_list_free(split);
+			return NULL;
+		}
+		if (kpargv_status(pargv) != KPARSE_OK) {
+			faux_error_sprintf(error, "%s",
+				kpargv_status_str(pargv));
+			kpargv_free(pargv);
+			faux_list_free(split);
+			return NULL;
+		}
+		// Only the first component can have 'restore=true' attribute
+		if ((iter != faux_list_head(split)) &&
+			kentry_restore(kpargv_command(pargv))) {
+			faux_error_sprintf(error, "The command \"%s\" "
+				"can't be desination of pipe",
+				kentry_name(kpargv_command(pargv)));
+			kpargv_free(pargv);
+			faux_list_free(split);
+			return NULL;
+		}
+
+		// Next component
+		iter = faux_list_next_node(iter);
+	}
+
+	faux_list_free(split);
+
+	return exec;
+}

+ 20 - 19
klish/ktp/ktpd_session.c

@@ -65,8 +65,8 @@ static bool_t ktpd_session_process_cmd(ktpd_session_t *session, faux_msg_t *msg)
 	faux_msg_t *ack = NULL;
 //	kpargv_t *pargv = NULL;
 	ktp_cmd_e cmd = KTP_CMD_ACK;
-
-	faux_list_t *split = NULL;
+	kexec_t *exec = NULL;
+	faux_error_t *error = NULL;
 
 	assert(session);
 	assert(msg);
@@ -78,24 +78,25 @@ static bool_t ktpd_session_process_cmd(ktpd_session_t *session, faux_msg_t *msg)
 		return BOOL_FALSE;
 	}
 
-	split = ksession_split_pipes(line);
-	printf("split %ld\n", split ? (ssize_t)faux_list_len(split) : -1);
-	faux_list_free(split);
-
-/*	// Parsing
-	pargv = ksession_parse_line(session->ksession, line, KPURPOSE_EXEC);
+	// Parsing
+	error = faux_error_new();
+	exec = ksession_parse_for_exec(session->ksession, line, error);
 	faux_str_free(line);
-	kpargv_debug(pargv);
-	if (kpargv_status(pargv) != KPARSE_OK) {
-		char *error = NULL;
-		error = faux_str_sprintf("Can't parse line: %s",
-			kpargv_status_str(pargv));
-		kpargv_free(pargv);
-		ktpd_session_send_error(session, cmd, error);
-		return BOOL_FALSE;
-	}
-	kpargv_free(pargv);
-*/
+//	kpargv_debug(pargv);
+//	if (kpargv_status(pargv) != KPARSE_OK) {
+//		char *error = NULL;
+//		error = faux_str_sprintf("Can't parse line: %s",
+//			kpargv_status_str(pargv));
+//		kpargv_free(pargv);
+//		ktpd_session_send_error(session, cmd, error);
+//		return BOOL_FALSE;
+//	}
+//
+//	kpargv_free(pargv);
+	faux_error_show(error);
+	kexec_free(exec);
+	faux_error_free(error);
+
 	// Send ACK message
 	ack = ktp_msg_preform(cmd, KTP_STATUS_NONE);
 	faux_msg_send_async(ack, session->async);