From 3821f764a8d8c7a0c3817d6cd754da35cbf72dee Mon Sep 17 00:00:00 2001 From: hellisabove Date: Mon, 10 Jan 2022 00:24:23 +0200 Subject: [PATCH] Initial Commit --- Makefile | 19 +++++ shell.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+) create mode 100644 Makefile create mode 100644 shell.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..38b3d28 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +OBJS = shell.o +SOURCE = shell.c +HEADER = +OUT = ss +CC = gcc +FLAGS = -g -c +LFLAGS = -lreadline + +all: $(OBJS) + $(CC) -g $(OBJS) -o $(OUT) $(LFLAGS) + +shell.o: shell.c + $(CC) $(FLAGS) shell.c + +install: all + cp ss /usr/local/bin + +clean: + rm -f $(OBJS) $(OUT) diff --git a/shell.c b/shell.c new file mode 100644 index 0000000..f2922eb --- /dev/null +++ b/shell.c @@ -0,0 +1,249 @@ +// C Program to design a shell in Linux +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXCOM 1000 // max number of letters to be supported +#define MAXLIST 100 // max number of commands to be supported + +// Clearing the shell using escape sequences +#define clear() printf("\033[H\033[J") + +// Function to take input +int takeInput(char* str) +{ + char* buf; + + buf = readline("\n$ "); + if (strlen(buf) != 0) { + add_history(buf); + strcpy(str, buf); + return 0; + } else { + return 1; + } +} + +// Function where the system command is executed +void execArgs(char** parsed) +{ + // Forking a child + pid_t pid = fork(); + + if (pid == -1) { + printf("\nFailed forking child.."); + return; + } else if (pid == 0) { + if (execvp(parsed[0], parsed) < 0) { + printf("\nCould not execute command.."); + } + exit(0); + } else { + // waiting for child to terminate + wait(NULL); + return; + } +} + +// Function where the piped system commands is executed +void execArgsPiped(char** parsed, char** parsedpipe) +{ + // 0 is read end, 1 is write end + int pipefd[2]; + pid_t p1, p2; + + if (pipe(pipefd) < 0) { + printf("\nPipe could not be initialized"); + return; + } + p1 = fork(); + if (p1 < 0) { + printf("\nCould not fork"); + return; + } + + if (p1 == 0) { + // Child 1 executing.. + // It only needs to write at the write end + close(pipefd[0]); + dup2(pipefd[1], STDOUT_FILENO); + close(pipefd[1]); + + if (execvp(parsed[0], parsed) < 0) { + printf("\nCould not execute command 1.."); + exit(0); + } + } else { + // Parent executing + p2 = fork(); + + if (p2 < 0) { + printf("\nCould not fork"); + return; + } + + // Child 2 executing.. + // It only needs to read at the read end + if (p2 == 0) { + close(pipefd[1]); + dup2(pipefd[0], STDIN_FILENO); + close(pipefd[0]); + if (execvp(parsedpipe[0], parsedpipe) < 0) { + printf("\nCould not execute command 2.."); + exit(0); + } + } else { + // parent executing, waiting for two children + wait(NULL); + wait(NULL); + } + } +} + +// Help command builtin +void openHelp() +{ + puts("\n***WELCOME TO MY SHELL HELP***" + "\nCopyright @ Suprotik Dey" + "\n-Use the shell at your own risk..." + "\nList of Commands supported:" + "\n>cd" + "\n>ls" + "\n>exit" + "\n>all other general commands available in UNIX shell" + "\n>pipe handling" + "\n>improper space handling"); + + return; +} + +// Function to execute builtin commands +int ownCmdHandler(char** parsed) +{ + int NoOfOwnCmds = 4, i, switchOwnArg = 0; + char* ListOfOwnCmds[NoOfOwnCmds]; + char* username; + + ListOfOwnCmds[0] = "exit"; + ListOfOwnCmds[1] = "cd"; + ListOfOwnCmds[2] = "help"; + ListOfOwnCmds[3] = "hello"; + + for (i = 0; i < NoOfOwnCmds; i++) { + if (strcmp(parsed[0], ListOfOwnCmds[i]) == 0) { + switchOwnArg = i + 1; + break; + } + } + + switch (switchOwnArg) { + case 1: + exit(0); + case 2: + chdir(parsed[1]); + return 1; + case 3: + openHelp(); + return 1; + case 4: + username = getenv("USER"); + printf("\nHello %s.\nMind that this is " + "not a place to play around." + "\nUse help to know more..\n", + username); + return 1; + default: + break; + } + + return 0; +} + +// function for finding pipe +int parsePipe(char* str, char** strpiped) +{ + int i; + for (i = 0; i < 2; i++) { + strpiped[i] = strsep(&str, "|"); + if (strpiped[i] == NULL) + break; + } + + if (strpiped[1] == NULL) + return 0; // returns zero if no pipe is found. + else { + return 1; + } +} + +// function for parsing command words +void parseSpace(char* str, char** parsed) +{ + int i; + + for (i = 0; i < MAXLIST; i++) { + parsed[i] = strsep(&str, " "); + + if (parsed[i] == NULL) + break; + if (strlen(parsed[i]) == 0) + i--; + } +} + +int processString(char* str, char** parsed, char** parsedpipe) +{ + + char* strpiped[2]; + int piped = 0; + + piped = parsePipe(str, strpiped); + + if (piped) { + parseSpace(strpiped[0], parsed); + parseSpace(strpiped[1], parsedpipe); + + } else { + + parseSpace(str, parsed); + } + + if (ownCmdHandler(parsed)) + return 0; + else + return 1 + piped; +} + +int main() +{ + char inputString[MAXCOM], *parsedArgs[MAXLIST]; + char* parsedArgsPiped[MAXLIST]; + int execFlag = 0; + + while (1) { + // take input + if (takeInput(inputString)) + continue; + // process + execFlag = processString(inputString, + parsedArgs, parsedArgsPiped); + // execflag returns zero if there is no command + // or it is a builtin command, + // 1 if it is a simple command + // 2 if it is including a pipe. + + // execute + if (execFlag == 1) + execArgs(parsedArgs); + + if (execFlag == 2) + execArgsPiped(parsedArgs, parsedArgsPiped); + } + return 0; +} +