Browse Source

Allow sync action within interactive commands

Serj Kalichev 1 year ago
parent
commit
463bbb3a8e
4 changed files with 24 additions and 16 deletions
  1. 2 2
      klish/kcontext.h
  2. 5 5
      klish/ksession/kcontext.c
  3. 16 8
      klish/ksession/kexec.c
  4. 1 1
      klish/ktp/ktpd_session.c

+ 2 - 2
klish/kcontext.h

@@ -75,8 +75,8 @@ bool_t kcontext_done(const kcontext_t *context);
 FAUX_HIDDEN bool_t kcontext_set_done(kcontext_t *context, bool_t done);
 
 // Pseudo Terminal Slave filename
-const char *kcontext_pts_fn(const kcontext_t *context);
-bool_t kcontext_set_pts_fn(kcontext_t *context, const char *pts_fn);
+const char *kcontext_pts_fname(const kcontext_t *context);
+bool_t kcontext_set_pts_fname(kcontext_t *context, const char *pts_fn);
 
 // Wrappers
 kparg_t *kcontext_candidate_parg(const kcontext_t *context);

+ 5 - 5
klish/ksession/kcontext.c

@@ -32,7 +32,7 @@ struct kcontext_s {
 	int stderr;
 	pid_t pid;
 	bool_t done; // If all actions are done
-	char *pts_fn; // Pseudo Terminal Slave file name
+	char *pts_fname; // Pseudo Terminal Slave file name
 };
 
 
@@ -94,8 +94,8 @@ KGET_BOOL(context, done);
 FAUX_HIDDEN KSET_BOOL(context, done);
 
 // PTS file name (Pseudo Terminal Slave)
-KSET_STR(context, pts_fn);
-KGET_STR(context, pts_fn);
+KSET_STR(context, pts_fname);
+KGET_STR(context, pts_fname);
 
 
 kcontext_t *kcontext_new(kcontext_type_e type)
@@ -122,7 +122,7 @@ kcontext_t *kcontext_new(kcontext_type_e type)
 	context->pid = -1; // PID of currently executed ACTION
 	context->session = NULL; // Don't free
 	context->done = BOOL_FALSE;
-	context->pts_fn = NULL;
+	context->pts_fname = NULL;
 
 	return context;
 }
@@ -141,7 +141,7 @@ void kcontext_free(kcontext_t *context)
 		close(context->stdout);
 	if (context->stderr != -1)
 		close(context->stderr);
-	faux_str_free(context->pts_fn);
+	faux_str_free(context->pts_fname);
 
 	faux_free(context);
 }

+ 16 - 8
klish/ksession/kexec.c

@@ -290,6 +290,7 @@ static bool_t kexec_prepare(kexec_t *exec)
 	// If command is interactive then prepare pseudoterminal. Note
 	// interactive commands can't have filters
 	if (kexec_interactive(exec)) {
+		int pts = -1;
 		int ptm = -1;
 		char *pts_name = NULL;
 		kcontext_t *context = (kcontext_t *)faux_list_data(
@@ -305,14 +306,23 @@ static bool_t kexec_prepare(kexec_t *exec)
 		grantpt(ptm);
 		unlockpt(ptm);
 		pts_name = ptsname(ptm);
+		// Open client side (pts) of pseudo terminal. It's necessary for
+		// sync action execution. Additionally open descriptor makes
+		// action (from child) to don't send SIGHUP on terminal handler.
+		pts = open(pts_name, O_RDWR, O_NOCTTY);
+		if (pts < 0)
+			return BOOL_FALSE;
 
 		kexec_set_stdin(exec, ptm);
 		kexec_set_stdout(exec, ptm);
 		kexec_set_stderr(exec, ptm);
-		// Don't set pts fd here. In a case of pseudo-terminal the pts
-		// must be opened later in the child after setsid(). So just
+		kcontext_set_stdin(context, pts);
+		kcontext_set_stdout(context, pts);
+		kcontext_set_stderr(context, pts);
+		// In a case of pseudo-terminal the pts
+		// must be reopened later in the child after setsid(). So just
 		// save filename of pts.
-		kcontext_set_pts_fn(context, pts_name);
+		kcontext_set_pts_fname(context, pts_name);
 		// Set pseudo terminal window size
 		kexec_set_winsize(exec);
 
@@ -320,8 +330,6 @@ static bool_t kexec_prepare(kexec_t *exec)
 	}
 
 	// Create "global" stdin, stdout, stderr for the whole job execution.
-	// Now function creates only the simple pipes but somedays it will be
-	// able to create pseudo-terminal for interactive sessions.
 
 	// STDIN
 	if (pipe(pipefd) < 0)
@@ -497,7 +505,7 @@ static bool_t exec_action_async(kcontext_t *context, const kaction_t *action,
 	pid_t child_pid = -1;
 	int i = 0;
 	int fdmax = 0;
-	const char *pts_fn = NULL;
+	const char *pts_fname = NULL;
 	sigset_t sigs = {};
 
 	fn = ksym_function(kaction_sym(action));
@@ -529,10 +537,10 @@ static bool_t exec_action_async(kcontext_t *context, const kaction_t *action,
 	sigemptyset(&sigs);
 	sigprocmask(SIG_SETMASK, &sigs, NULL);
 
-	if ((pts_fn = kcontext_pts_fn(context)) != NULL) {
+	if ((pts_fname = kcontext_pts_fname(context)) != NULL) {
 		int fd = -1;
 		setsid();
-		fd = open(pts_fn, O_RDWR, 0);
+		fd = open(pts_fname, O_RDWR, 0);
 		if (fd < 0)
 			_exit(-1);
 		dup2(fd, STDIN_FILENO);

+ 1 - 1
klish/ktp/ktpd_session.c

@@ -1170,7 +1170,7 @@ static bool_t action_stdout_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
 	// EOF || POLERR || POLLNVAL
 	if (info->revents & (POLLHUP | POLLERR | POLLNVAL)) {
 		faux_eloop_del_fd(eloop, info->fd);
-		syslog(LOG_DEBUG, "Close fd %d", info->fd);
+//		syslog(LOG_DEBUG, "Close fd %d (%x)", info->fd, info->revents);
 	}
 
 	// Happy compiler