Browse Source

pty: Fix client stdin

Serj Kalichev 1 year ago
parent
commit
0a8227e36b
2 changed files with 65 additions and 13 deletions
  1. 45 1
      bin/klish/interactive.c
  2. 20 12
      klish/ktp/ktp_session.c

+ 45 - 1
bin/klish/interactive.c

@@ -30,6 +30,7 @@ typedef struct ctx_s {
 
 bool_t auth_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata);
 bool_t cmd_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata);
+bool_t cmd_incompleted_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata);
 bool_t completion_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata);
 bool_t help_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata);
 static bool_t stdin_cb(faux_eloop_t *eloop, faux_eloop_type_e type,
@@ -99,7 +100,10 @@ int klish_interactive_shell(ktp_session_t *ktp, struct options *opts)
 	ktp_session_set_stop_on_answer(ktp, BOOL_FALSE);
 
 	ktp_session_set_cb(ktp, KTP_SESSION_CB_CMD_ACK, cmd_ack_cb, &ctx);
-	ktp_session_set_cb(ktp, KTP_SESSION_CB_COMPLETION_ACK, completion_ack_cb, &ctx);
+	ktp_session_set_cb(ktp, KTP_SESSION_CB_CMD_ACK_INCOMPLETED,
+		cmd_incompleted_ack_cb, &ctx);
+	ktp_session_set_cb(ktp, KTP_SESSION_CB_COMPLETION_ACK,
+		completion_ack_cb, &ctx);
 	ktp_session_set_cb(ktp, KTP_SESSION_CB_HELP_ACK, help_ack_cb, &ctx);
 
 	tinyrl_redisplay(tinyrl);
@@ -220,6 +224,10 @@ bool_t auth_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata)
 	}
 	faux_error_free(error);
 
+	// Operation is finished so restore stdin handler
+	faux_eloop_add_fd(ktp_session_eloop(ktp), STDIN_FILENO, POLLIN,
+		stdin_cb, ctx);
+
 	// Happy compiler
 	msg = msg;
 
@@ -258,6 +266,28 @@ bool_t cmd_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata)
 	if (!ktp_session_done(ktp))
 		tinyrl_redisplay(ctx->tinyrl);
 
+	// Operation is finished so restore stdin handler
+	faux_eloop_add_fd(ktp_session_eloop(ktp), STDIN_FILENO, POLLIN,
+		stdin_cb, ctx);
+
+	// Happy compiler
+	msg = msg;
+
+	return BOOL_TRUE;
+}
+
+
+bool_t cmd_incompleted_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata)
+{
+	ctx_t *ctx = (ctx_t *)udata;
+
+	// Interactive command. So restore stdin handler.
+	if ((ktp_session_state(ktp) == KTP_SESSION_STATE_WAIT_FOR_CMD) &&
+		KTP_STATUS_IS_INTERACTIVE(ktp_session_cmd_features(ktp))) {
+		faux_eloop_add_fd(ktp_session_eloop(ktp), STDIN_FILENO, POLLIN,
+			stdin_cb, ctx);
+	}
+
 	// Happy compiler
 	msg = msg;
 
@@ -294,8 +324,14 @@ static bool_t stdin_cb(faux_eloop_t *eloop, faux_eloop_type_e type,
 			if (bytes_readed != sizeof(buf))
 				break;
 		}
+		return BOOL_TRUE;
 	}
 
+	// Here the situation when input is not allowed. Remove stdin from
+	// eloop waiting list. Else klish will get 100% CPU. Callbacks on
+	// operation completions will restore this handler.
+	faux_eloop_del_fd(eloop, STDIN_FILENO);
+
 	// Happy compiler
 	eloop = eloop;
 	type = type;
@@ -505,6 +541,10 @@ bool_t completion_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata)
 	faux_list_free(completions);
 	faux_str_free(prefix);
 
+	// Operation is finished so restore stdin handler
+	faux_eloop_add_fd(ktp_session_eloop(ktp), STDIN_FILENO, POLLIN,
+		stdin_cb, ctx);
+
 	// Happy compiler
 	ktp = ktp;
 	msg = msg;
@@ -587,6 +627,10 @@ bool_t help_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata)
 
 	faux_list_free(help_list);
 
+	// Operation is finished so restore stdin handler
+	faux_eloop_add_fd(ktp_session_eloop(ktp), STDIN_FILENO, POLLIN,
+		stdin_cb, ctx);
+
 	ktp = ktp; // happy compiler
 
 	return BOOL_TRUE;

+ 20 - 12
klish/ktp/ktp_session.c

@@ -596,7 +596,8 @@ static bool_t ktp_session_read_cb(faux_async_t *async,
 
 
 static bool_t ktp_session_req(ktp_session_t *ktp, ktp_cmd_e cmd,
-	const char *line, size_t line_len, faux_error_t *error, bool_t dry_run)
+	const char *line, size_t line_len, faux_error_t *error,
+	bool_t dry_run, bool_t drop_state)
 {
 	faux_msg_t *req = NULL;
 	ktp_status_e status = KTP_STATUS_NONE;
@@ -616,12 +617,14 @@ static bool_t ktp_session_req(ktp_session_t *ktp, ktp_cmd_e cmd,
 	faux_msg_free(req);
 
 	// Prepare for loop
-	ktp->error = error;
-	ktp->cmd_retcode = -1;
-	ktp->cmd_retcode_available = BOOL_FALSE;
-	ktp->request_done = BOOL_FALSE;
-	ktp->cmd_features = KTP_STATUS_NONE;
-	ktp->cmd_features_available = BOOL_FALSE;
+	if (drop_state) {
+		ktp->error = error;
+		ktp->cmd_retcode = -1;
+		ktp->cmd_retcode_available = BOOL_FALSE;
+		ktp->request_done = BOOL_FALSE;
+		ktp->cmd_features = KTP_STATUS_NONE;
+		ktp->cmd_features_available = BOOL_FALSE;
+	}
 
 	return BOOL_TRUE;
 }
@@ -630,7 +633,8 @@ static bool_t ktp_session_req(ktp_session_t *ktp, ktp_cmd_e cmd,
 bool_t ktp_session_cmd(ktp_session_t *ktp, const char *line,
 	faux_error_t *error, bool_t dry_run)
 {
-	if (!ktp_session_req(ktp, KTP_CMD, line, strlen(line), error, dry_run))
+	if (!ktp_session_req(ktp, KTP_CMD, line, strlen(line),
+		error, dry_run, BOOL_TRUE))
 		return BOOL_FALSE;
 	ktp->state = KTP_SESSION_STATE_WAIT_FOR_CMD;
 
@@ -640,7 +644,8 @@ bool_t ktp_session_cmd(ktp_session_t *ktp, const char *line,
 
 bool_t ktp_session_auth(ktp_session_t *ktp, faux_error_t *error)
 {
-	if (!ktp_session_req(ktp, KTP_AUTH, NULL, 0, error, BOOL_FALSE))
+	if (!ktp_session_req(ktp, KTP_AUTH, NULL, 0,
+		error, BOOL_FALSE, BOOL_TRUE))
 		return BOOL_FALSE;
 	ktp->state = KTP_SESSION_STATE_UNAUTHORIZED;
 
@@ -650,7 +655,8 @@ bool_t ktp_session_auth(ktp_session_t *ktp, faux_error_t *error)
 
 bool_t ktp_session_completion(ktp_session_t *ktp, const char *line, bool_t dry_run)
 {
-	if (!ktp_session_req(ktp, KTP_COMPLETION, line, strlen(line), NULL, dry_run))
+	if (!ktp_session_req(ktp, KTP_COMPLETION, line, strlen(line),
+		NULL, dry_run, BOOL_TRUE))
 		return BOOL_FALSE;
 	ktp->state = KTP_SESSION_STATE_WAIT_FOR_COMPLETION;
 
@@ -660,7 +666,8 @@ bool_t ktp_session_completion(ktp_session_t *ktp, const char *line, bool_t dry_r
 
 bool_t ktp_session_help(ktp_session_t *ktp, const char *line)
 {
-	if (!ktp_session_req(ktp, KTP_HELP, line, strlen(line), NULL, BOOL_TRUE))
+	if (!ktp_session_req(ktp, KTP_HELP, line, strlen(line),
+		NULL, BOOL_TRUE, BOOL_TRUE))
 		return BOOL_FALSE;
 	ktp->state = KTP_SESSION_STATE_WAIT_FOR_HELP;
 
@@ -670,7 +677,8 @@ bool_t ktp_session_help(ktp_session_t *ktp, const char *line)
 
 bool_t ktp_session_stdin(ktp_session_t *ktp, const char *line, size_t line_len)
 {
-	if (!ktp_session_req(ktp, KTP_STDIN, line, line_len, NULL, BOOL_TRUE))
+	if (!ktp_session_req(ktp, KTP_STDIN, line, line_len,
+		NULL, BOOL_TRUE, BOOL_FALSE))
 		return BOOL_FALSE;
 
 	return BOOL_TRUE;