Browse Source

Basic architecture impl, initialisation process full impl

Ivan Arkhipov 4 years ago
parent
commit
7f42ad0265
12 changed files with 347 additions and 0 deletions
  1. 22 0
      CMakeLists.txt
  2. 0 0
      esh_constants.h
  3. 5 0
      esh_deinit.c
  4. 7 0
      esh_deinit.h
  5. 104 0
      esh_init.c
  6. 12 0
      esh_init.h
  7. 41 0
      esh_main_loop.c
  8. 26 0
      esh_main_loop.h
  9. 45 0
      esh_misc.c
  10. 21 0
      esh_misc.h
  11. 54 0
      esh_types.h
  12. 10 0
      main.c

+ 22 - 0
CMakeLists.txt

@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.14)
+project(shell C)
+
+set(CMAKE_C_STANDARD 11)
+
+include_directories(.)
+
+file(STRINGS .git/refs/heads/master BuildRef)
+add_compile_definitions(BUILD_REF="${BuildRef}")
+
+add_executable(shell
+        esh_deinit.c
+        esh_deinit.h
+        esh_init.c
+        esh_init.h
+        esh_main_loop.c
+        esh_main_loop.h
+        esh_misc.c
+        esh_misc.h
+        esh_types.h
+        main.c
+)

+ 0 - 0
esh_constants.h


+ 5 - 0
esh_deinit.c

@@ -0,0 +1,5 @@
+#include "esh_deinit.h"
+
+void EShDeinit() {
+	
+}

+ 7 - 0
esh_deinit.h

@@ -0,0 +1,7 @@
+#ifndef ESH_DEINIT_H
+#define ESH_DEINIT_H
+
+void EShDeinit();
+
+
+#endif // ESH_DEINIT_H

+ 104 - 0
esh_init.c

@@ -0,0 +1,104 @@
+#include "esh_types.h"
+#include "esh_misc.h"
+#include "esh_init.h"
+	
+EShInfo* esh_info_global;
+
+void EShInit(int argc, char** argv) {
+	EShInitInfo(argc, argv);
+	EShParseCommandLineArgs(argc, argv);
+	EShProcessConfigFile();
+
+	printf("===================================\n"
+		   "Hello, %s!\n"
+		   "This is Endevir Shell (ESh)\n"
+		   "ESh build %.8s\n"
+		   "\n"
+		   "Home directory: %s\n"
+		   "Default shell program: %s\n"
+		   "Config file path: %s\n"
+		   "Commands history file path: %s\n"
+		   "===================================\n",
+		   esh_info_global->user_data->pw_name, 
+		   esh_info_global->build_ref,
+		   esh_info_global->user_data->pw_dir,
+		   esh_info_global->user_data->pw_shell,
+		   esh_info_global->config_file_path,
+		   esh_info_global->history_file_path);
+}
+ 
+void EShInitInfo(int argc, char** argv) {
+	esh_info_global = malloc(sizeof(EShInfo));
+	
+	esh_info_global->build_ref = malloc((strlen(BUILD_REF) + 1) * sizeof(char));
+	strcpy(esh_info_global->build_ref, BUILD_REF);
+
+	esh_info_global->user_data = getpwuid(geteuid());
+	
+
+	esh_info_global->current_working_dir = malloc((PATH_MAX + 1) * sizeof(char));
+	memset(esh_info_global->current_working_dir, 0, (PATH_MAX + 1) * sizeof(char));
+	getcwd(esh_info_global->current_working_dir, PATH_MAX);
+	EShOptimiseCurrentWorkingDirectory();
+
+	esh_info_global->config_file_path = malloc((PATH_MAX + 1) * sizeof(char));
+	memset(esh_info_global->config_file_path, 0, (PATH_MAX + 1) * sizeof(char));
+	strcat(esh_info_global->config_file_path, esh_info_global->user_data->pw_dir);
+	strcat(esh_info_global->config_file_path, "/.esh_conf");
+	
+	esh_info_global->history_file_path = malloc((PATH_MAX + 1) * sizeof(char));
+	memset(esh_info_global->history_file_path, 0, (PATH_MAX + 1) * sizeof(char));
+	strcat(esh_info_global->history_file_path, esh_info_global->user_data->pw_dir);
+	strcat(esh_info_global->history_file_path, "/.esh_history");
+
+	esh_info_global->history_limit = 5000;
+
+	esh_info_global->max_jobs_number = 64;
+
+	esh_info_global->jobs_number = 0;
+
+	esh_info_global->max_invite_message_len = 2048;
+
+	esh_info_global->invite_message = malloc((esh_info_global->max_invite_message_len + 1) * sizeof(char));
+	EShUpdateInviteMessage();
+
+	esh_info_global->exited = 0;
+}
+
+void EShParseCommandLineArgs(int argc, char** argv) {
+	for (int i = 1; i < argc; i += 2) {
+		if (strcmp(argv[i], "-h") == 0) {
+			EShShowHelpAndExit();
+		}
+
+		if (i + 1 >= argc) {
+			printf("ERROR: Incorrect command-line parameters number!");
+			exit(1);
+		}
+
+		if (strcmp(argv[i], "-config") == 0) {
+			strcpy(esh_info_global->config_file_path, argv[i + 1]);
+		}
+
+		if (strcmp(argv[i], "-history_path") == 0) {
+			strcpy(esh_info_global->history_file_path, argv[i + 1]);
+		}
+
+		if (strcmp(argv[i], "-history_limit") == 0) {
+			sscanf(argv[i + 1], "%d", &esh_info_global->history_limit);
+		}
+
+		if (strcmp(argv[i], "-max_active_jobs") == 0) {
+			sscanf(argv[i + 1], "%d", &esh_info_global->max_jobs_number);
+		}
+	}
+}
+
+void EShProcessConfigFile() {
+	FILE* file = fopen(esh_info_global->config_file_path, "r");
+	if (!file) {
+		return;
+	}
+
+	fclose(file);
+}

+ 12 - 0
esh_init.h

@@ -0,0 +1,12 @@
+#ifndef ESH_INIT_H
+#define ESH_INIT_H
+
+void EShInit(int argc, char** argv);
+
+void EShInitInfo();
+
+void EShParseCommandLineArgs(int argc, char** argv);
+
+void EShProcessConfigFile();
+
+#endif // ESH_INIT_H

+ 41 - 0
esh_main_loop.c

@@ -0,0 +1,41 @@
+#include "esh_main_loop.h"
+
+void EShRunLoop() {
+
+}
+
+void EShShowMsg() {
+
+}
+
+void EShParseCommandIntoJobs(char* command) {
+
+}
+
+void EShExecuteJobs(int jobs_num, EShJob* jobs_list) {
+
+}
+
+void EShSetJobCommandType(EShJob* job) {
+
+}
+
+void EShRunJob(EShJob* job) {
+
+}
+
+int EmptyCommand(const char* command) {
+
+}
+
+int InnerCommand(const char* command) {
+
+}
+
+void EShProcessInnerJob(const char* command) {
+
+}
+
+void EShProcessExecJob(const char* command) {
+	
+}

+ 26 - 0
esh_main_loop.h

@@ -0,0 +1,26 @@
+#include "esh_types.h"
+
+#ifndef ESH_MAIN_LOOP_H
+#define ESH_MAIN_LOOP_H
+
+void EShRunLoop();
+
+void EShShowMsg();
+
+void EShParseCommandIntoJobs(char* command);
+
+void EShExecuteJobs(int jobs_num, EShJob* jobs_list);
+
+void EShSetJobCommandType(EShJob* job);
+
+void EShRunJob(EShJob* job);
+
+int EmptyCommand(const char* command);
+
+int InnerCommand(const char* command);
+
+void EShProcessInnerJob(const char* command);
+
+void EShProcessExecJob(const char* command);
+
+#endif // ESH_MAIN_LOOP_H

+ 45 - 0
esh_misc.c

@@ -0,0 +1,45 @@
+#include "esh_misc.h"
+
+void EShOptimiseCurrentWorkingDirectory() {
+	if (strstr(esh_info_global->current_working_dir, esh_info_global->user_data->pw_dir) == esh_info_global->current_working_dir) {
+		char new_cwd[PATH_MAX + 1];
+		memset(new_cwd, 0, PATH_MAX + 1);
+		strcat(new_cwd, "~");
+		strcat(new_cwd, esh_info_global->current_working_dir + strlen(esh_info_global->user_data->pw_dir));
+		strcpy(esh_info_global->current_working_dir, new_cwd);
+	}
+}
+
+void EShUpdateInviteMessage() {
+	memset(esh_info_global->invite_message, 0, (esh_info_global->max_invite_message_len + 1) * sizeof(char));
+	strcat(esh_info_global->invite_message, ANSI_COLOR_BLUE);
+	strcat(esh_info_global->invite_message, esh_info_global->user_data->pw_name);
+	strcat(esh_info_global->invite_message, ANSI_COLOR_RESET);
+	strcat(esh_info_global->invite_message, "@");
+	strcat(esh_info_global->invite_message, ANSI_COLOR_GREEN);
+	strcat(esh_info_global->invite_message, esh_info_global->current_working_dir);
+	strcat(esh_info_global->invite_message, ANSI_COLOR_RESET);
+	strcat(esh_info_global->invite_message, " » ");
+}
+
+void EShShowHelpAndExit() {
+	printf(ANSI_COLOR_RED "ESh (Endevir Shell) build %.8s\n" ANSI_COLOR_RESET
+		   "\n"
+		   "Usage: esh [-h] [-config FILENAME] [-history FILENAME] [-history_limit INT] [-max_active_jobs INT]\n"
+		   "\n"
+		   "Description:\n"
+		   "This is a simple shell, written in C\n"
+		   "\n"
+		   "Parameters:\n"
+		   "-h                          shows this message and exits\n"
+		   "-config FILENAME            uses file with name FILENAME as config file (default: ~/.esh_conf)\n"
+		   "-history_path FILENAME      uses file with name FILENAME as storage for entered commands history (default: ~/.esh_history)\n"
+		   "-history_limit INT          limits commands number to keep up to INT (default: 5000 lines)\n"
+		   "-max_active_jobs INT        limits shell active jobs number up to INT (default: 64)\n"
+		   "\n"
+		   "\n"
+		   "Copyleft. Written by Ivan Arkhipov aka Endevir (me@endevir.ru), MIPT, Dolgoprudny, Russia, 2019.\n",
+		   esh_info_global->build_ref);
+
+   	exit(0);
+}

+ 21 - 0
esh_misc.h

@@ -0,0 +1,21 @@
+#include "esh_types.h"
+
+#ifndef ESH_MISC_H
+#define ESH_MISC_H
+
+#define ANSI_COLOR_RED     "\x1b[31m"
+#define ANSI_COLOR_GREEN   "\x1b[32m"
+#define ANSI_COLOR_YELLOW  "\x1b[33m"
+#define ANSI_COLOR_BLUE    "\x1b[34m"
+#define ANSI_COLOR_MAGENTA "\x1b[35m"
+#define ANSI_COLOR_CYAN    "\x1b[36m"
+#define ANSI_COLOR_RESET   "\x1b[0m"
+
+void EShOptimiseCurrentWorkingDirectory(); // Replaces user home folder path in esh_info_global->current_working_dir with ~
+
+void EShUpdateInviteMessage(); // Update input invite message (ex. should be called on username/cwd change)
+
+void EShShowHelpAndExit(); // Prints help to stdout and exits
+
+
+#endif // ESH_MISC_H

+ 54 - 0
esh_types.h

@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <pthread.h>
+#include <time.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#ifndef ESH_TYPES_H
+#define ESH_TYPES_H
+
+typedef enum {
+	BACKGROUND,
+	FOREGROUND
+} ESH_JOB_TYPE;
+
+typedef enum {
+	INNER_CMD,
+	EXEC_CMD
+} ESH_COMMAND_TYPE;
+
+typedef struct {
+	char* command;
+	ESH_COMMAND_TYPE command_type;
+	ESH_JOB_TYPE job_type;
+	pid_t job_pid;
+
+	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.
+} EShJob;
+
+typedef struct {
+	char* build_ref;
+	struct passwd* user_data;
+	char* current_working_dir;
+
+	char* config_file_path; // path to file, containing configurations (changeable via settings/cmd line args)
+	char* history_file_path; // path to file, where entered commands history is stored (changeable via settings/cmd line args)
+	int history_limit; // max lines of commands, which can be stored (changeable via settings/cmd line args)
+	int max_jobs_number; // max active jobs (foreground & background) limit (changeable via settings/cmd line args)
+
+	int max_invite_message_len;
+	char* invite_message;
+
+	int jobs_number;
+	EShJob* jobs_list;
+
+	int exited; // used to stop threads on exiting 
+} EShInfo;
+
+extern EShInfo* esh_info_global;
+
+#endif // ESH_TYPES_H

+ 10 - 0
main.c

@@ -0,0 +1,10 @@
+#include "esh_init.h"
+#include "esh_main_loop.h"
+#include "esh_deinit.h"
+
+int main(int argc, char** argv) {
+	EShInit(argc, argv);
+	EShRunLoop();
+	EShDeinit();
+	return 0;
+}