Browse Source

Added pipes functionality

Ivan Arkhipov 4 years ago
parent
commit
790a4eb25d
5 changed files with 91 additions and 48 deletions
  1. 15 0
      esh_deinit.c
  2. 3 5
      esh_init.c
  3. 68 23
      esh_main_loop.c
  4. 1 7
      esh_misc.c
  5. 4 13
      esh_types.h

+ 15 - 0
esh_deinit.c

@@ -49,6 +49,21 @@ void EShDeinitJob(EShJob* job) {
 	if (!job)
 		return;
 
+	if (job->stdin_fd != -1) {
+		close(job->stdin_fd);
+		job->stdin_fd = -1;
+	}
+
+	if (job->stdout_fd != -1) {
+		close(job->stdout_fd);
+		job->stdout_fd = -1;
+	}
+	
+	if (job->stderr_fd != -1) {
+		close(job->stderr_fd);
+		job->stderr_fd = -1;
+	}
+
 	free(job->command);
 
 	for (int i = 0; i < esh_info_global->max_command_tokens; ++i) {

+ 3 - 5
esh_init.c

@@ -181,18 +181,16 @@ void EShInitJob(EShJob* job) {
 	}
 	job->command_tokens_num = 0;
 
-	job->command_type = EXEC_CMD;
 	job->job_type = FOREGROUND;
 	job->job_start_condition = NO_CONDITION;
 
 	job->job_pid = -1;
 
-	job->job_stdin = NULL;
-	job->job_stdout = NULL;
-	job->job_stderr = NULL;
+	job->stdin_fd = -1;
+	job->stdout_fd = -1;
+	job->stderr_fd = -1;
 }
 
-
 EShJob* EShMakeJobsList() {
 	EShJob* jobs_list = malloc(esh_info_global->max_jobs_number * sizeof(EShJob));
 	for (int i = 0; i < esh_info_global->max_jobs_number; ++i) {

+ 68 - 23
esh_main_loop.c

@@ -225,11 +225,15 @@ EShJob* EShParseCommandIntoJobs(char* command, int* jobs_num) {
 			}
 
 			if (delimiter == BIT_OR) {
-				printf(ANSI_COLOR_RED "\nESh note: running processes through pipes is still not available, you will need to enter data manually :(\n" ANSI_COLOR_RESET);
-				fflush(stdout);
-			}
+				int pipes[2];
+				if (pipe(pipes) != 0) {
+					printf(ANSI_COLOR_RED "\nESh error: cannot spawn pipe: %s\n" ANSI_COLOR_RESET, strerror(errno));
+					fflush(stdout);
+				}
 
-			// TODO: delimiter == BIT_OR and BIT_AND
+				jobs[*jobs_num - 1].stdout_fd = pipes[1];
+				jobs[*jobs_num].stdin_fd = pipes[0];
+			}
 			
 			++(*jobs_num);
 			current_job_cmd_length = 0;
@@ -281,8 +285,18 @@ void EShSplitJobCommand(EShJob* job, char delim) {
 }
 
 void EShExecuteJobs(int jobs_num, EShJob* jobs_list) {
+	int prev_job_exit_code = 0;
+
 	for (int i = 0;  i < jobs_num; ++i) {
-		EShRunJob(&jobs_list[i]);
+		if (strlen(jobs_list[i].command) == 0)
+			continue;
+
+		if (jobs_list[i].job_start_condition == NO_CONDITION ||
+			(jobs_list[i].job_start_condition == PREVIOUS_EXIT_SUCCESS && prev_job_exit_code == 0) ||
+			(jobs_list[i].job_start_condition == PREVIOUS_EXIT_FAILED && prev_job_exit_code != 0)) 
+		{
+			EShRunJob(&jobs_list[i]);
+		}
 	}
 }
 
@@ -292,9 +306,9 @@ void EShSetJobCommandType(EShJob* job) {
 
 int EShRunJob(EShJob* job) {
 	if (EShIsInnerJob(job)) {
-		EShProcessInnerJob(job);
+		return EShProcessInnerJob(job);
 	} else {
-		EShProcessExecJob(job);
+		return EShProcessExecJob(job);
 	}
 	// TODO: PIPES INIT & BG PROCESS SUPPORT
 }
@@ -308,13 +322,12 @@ int EShIsInnerJob(EShJob* job) {
 
 int EShProcessInnerJob(EShJob* job) {
 	if (strcmp(job->command_tokens[0], "cd") == 0) {
-
-		if (job->command_tokens_num < 2) {
-			printf(ANSI_COLOR_RED "Esh: cannot change directory, no directory specified.\n" ANSI_COLOR_RESET, job->command);
+		if (chdir(job->command_tokens[1]) == -1) {
+			printf(ANSI_COLOR_RED "Esh: cannot change directory: %s\n" ANSI_COLOR_RESET, strerror(errno));
 			fflush(stdout);
+			return -1;
 		}
 
-		chdir(job->command_tokens[1]);
 		getcwd(esh_info_global->current_working_dir, PATH_MAX);
 		EShOptimiseCurrentWorkingDirectory();
 		EShUpdateInviteMessage();
@@ -330,6 +343,24 @@ int EShProcessInnerJob(EShJob* job) {
 int EShProcessExecJob(EShJob* job) {
 	int pid = fork();
 	if (pid == 0) {
+		if (job->stdin_fd != -1) {
+			dup2(job->stdin_fd, STDIN_FILENO);
+			close(job->stdin_fd);
+			job->stdin_fd = -1;
+		}
+
+		if (job->stdout_fd != -1) {
+			dup2(job->stdout_fd, STDOUT_FILENO);
+			close(job->stdout_fd);
+			job->stdout_fd = -1;
+		}
+
+		if (job->stderr_fd != -1) {
+			dup2(job->stderr_fd, STDERR_FILENO);
+			close(job->stderr_fd);
+			job->stderr_fd = -1;
+		}
+
 		for (int i = job->command_tokens_num; i < esh_info_global->max_command_tokens; ++i) {
 			free(job->command_tokens[i]);
 			job->command_tokens[i] = NULL;
@@ -340,27 +371,41 @@ int EShProcessExecJob(EShJob* job) {
 		fflush(stdout);
 		exit(1); // execlp failed
 	} else {
-		waitpid(pid, NULL, 0);
-		printf("\n");
+		if (job->stdin_fd != -1) {
+			close(job->stdin_fd);
+			job->stdin_fd = -1;
+		}
+
+		if (job->stdout_fd != -1) {
+			close(job->stdout_fd);
+			job->stdout_fd = -1;
+		}
+
+		if (job->stderr_fd != -1) {
+			close(job->stderr_fd);
+			job->stderr_fd = -1;
+		}
+
+		job->job_pid = pid;
+	    int status;
+		waitpid(pid, &status, 0);
+      
+	    if (WIFEXITED(status)) { 
+	        return  WEXITSTATUS(status);         
+	    } else {
+	    	return -1; // No exit status received;
+	    } 
 	}
 }
 
 
 void EShSubstituteShellValuesArgument(char** arg) {
- 	// Processing tilda
-	// char* tilda_pos;
-	// while ((tilda_pos = strchr(arg, '~')) != NULL) {
-	// 	for (int i = strlen(arg); i > (tilda_pos - arg); --i) {
-	// 		arg[i + strlen(esh_info_global->user_data->pw_dir)] = arg[i];
-	// 	}
-	// 	memcpy(tilda_pos, esh_info_global->user_data->pw_dir, strlen(esh_info_global->user_data->pw_dir));
-	// }
-
 	char* new_str = *arg;
+
+ 	// Processing tilda
 	new_str = repl_str(new_str, "~", esh_info_global->user_data->pw_dir);
 
 	// Processing system variables
-	
 	char* envvar_begin = new_str - 1;
 	while ((envvar_begin = strchr(envvar_begin + 1, '%')) != NULL) {
 		char* envvar_end = strchr(envvar_begin + 1, '%');

+ 1 - 7
esh_misc.c

@@ -46,12 +46,7 @@ void EShShowHelpAndExit() {
 }
 
 int EShIsShellLetter(char c) { // TODO: Russian symbols
-	return (c >= 'a' && c <= 'z') || 
-		   (c >= 'A' && c <= 'Z') || 
-		   (c >= '0' && c <= '9') || 
-		   (c >= ' ' && c <= '/') ||
-		   (c >= ':' && c <= '?') || 
-		   (c == '|') || (c == '\\') || (c == '~');
+	return (c >= 32 && c <= 127);
 } 
 
 ESH_JOB_DELIMITER EshIsJobDelimiter(char* c) {
@@ -89,4 +84,3 @@ int EShGetJobDelimiterSize(ESH_JOB_DELIMITER delim) {
 
 	return 0;
 }
-

+ 4 - 13
esh_types.h

@@ -7,6 +7,7 @@
 #include <unistd.h>
 #include <limits.h>
 #include <termios.h>
+#include <errno.h>
 
 #include <sys/wait.h>
 
@@ -18,11 +19,6 @@ typedef enum {
 	FOREGROUND
 } ESH_JOB_TYPE;
 
-typedef enum {
-	INNER_CMD,
-	EXEC_CMD
-} ESH_COMMAND_TYPE;
-
 typedef enum {
 	NO_CONDITION, // ex. commands delimited by ';' 
 	PREVIOUS_EXIT_SUCCESS, // ex. commands delimited by '&&'
@@ -43,19 +39,14 @@ typedef struct {
 	char** command_tokens;
 	int command_tokens_num;
 
-	ESH_COMMAND_TYPE command_type;
 	ESH_JOB_TYPE job_type;
 	ESH_JOB_CONDITION job_start_condition;
 
 	pid_t job_pid;
 
-	FILE* job_stdin;
-	FILE* job_stdout;
-	FILE* job_stderr;
-
-	int stdin_pipe[2];
-	int stdout_pipe[2]; // 0 is for writing in child process and for reading in parent process.
-	int stderr_pipe[2];	// 1 is for writing in parent process and for reading in child process.
+	int stdin_fd;
+	int stdout_fd;
+	int stderr_fd;
 } EShJob;
 
 typedef struct {